NDK(19)简单示例:ndk调用java基本方法、数组;使用stl、访问设备
一、ndk调用java类示例
1,调用基本方法
/*
* Class: com_example_ndksample_MainActivity
* Method: ndkFindJavaClass
* Signature: ()Ljava/lang/String;
*/
/*
* ndk主动查找java类并调用.
*/
JNIEXPORT jstring JNICALL Java_com_example_ndksample_MainActivity_ndkFindJavaClass
(JNIEnv *env, jobject mainActivity)
{
jint age ;
jfieldID field;
jmethodID mid; //1,找到java中相关的类,
//用全类名找,包名中的.改成/ 如com/example/ndksample/NdkCallJava
jclass cls = env->FindClass("com/example/ndksample/NdkCallJava");
if (env->ExceptionCheck() ) {
return env->NewStringUTF("NdkCallJava not found \n");
}
//2,在相关类中找到field field = env->GetStaticFieldID(cls, "age", "I");
if (env->ExceptionCheck() ) {
return env->NewStringUTF("age not found \n");
}
//3,用field访问该属性
age = env->GetStaticIntField(cls,field); //如果不是静态属性直接用env->GetIntField(jobject obj, jfieldID fieldID);
__android_log_print(ANDROID_LOG_ERROR, __func__,"age = %d\n", age); //4,找到java 中的方法
/*
* 找到public void ageFromNdk(int ageFromNdk)后会调用失败,因为它是非静态的.
* 非静态成员要用jobject调用,同时这个对象没有从java中传来,所以这里不能正常调用,
* 只能用jclass调用静态的 public void ageFromNdkStatic(int ageFromNdk);
* 可以用env new一个类型为"com/example/ndksample/NdkCallJava"的jobject,
* 但这个 jobject只是ndk中的并不是java中的,用它调用了也不是所期待的那个.
*/
const char * method = "ageFromNdkStatic"; //它虽然是个private的,但可调用
mid = env->GetStaticMethodID(cls, method, "(I)V");
if (env->ExceptionCheck() ) {
__android_log_print(ANDROID_LOG_ERROR, __func__,"%s not found\n",method);
return env->NewStringUTF("ageFromNdkStatic not found \n");
}
//5,调用java中的静态方法
int newAge = ;//这个是传给 ageFromNdkStatic(int ageFromNdk) 的参数
env->CallStaticVoidMethod(cls,mid,newAge);
age = env->GetStaticIntField(cls,field);//重新取age的值 //6,返回的结果
char result[]={};
sprintf(result,"%s : %d\n","ndkFindJavaClass",age);
return env->NewStringUTF(result);
}
/*
* Class: com_example_ndksample_MainActivity
* Method: testClassAndMethod
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_ndksample_MainActivity_testClassAndMethod
(JNIEnv *env, jobject mainActivity)
{
/*
* 注意函数参数的传递及如何保存java函数返回值,
*/
jclass clazz ;
jobject javaObj;
jmethodID constructor;
jmethodID show ;
//1,构造对象第1步: 找到相关class
clazz = env->FindClass("com/example/ndksample/JavaSchool");
if (env->ExceptionCheck() ) {
return env->NewStringUTF("find class exception \n");
}
//2,构造对象第2步: 选定class中的一个构造函数
/*
* public JavaSchool(Context context)
* 所有类的构造函数名只能是<init>
*/
constructor = env->GetMethodID(clazz,"<init>","(Landroid/content/Context;)V");
if (env->ExceptionCheck() ) {
return env->NewStringUTF("method <init> exception \n");
}
//3,构造对象第3步: 为构造函数准备参数 Context context,,这里mainActivity就是
//4,构造对象第4步: env->NewObject(clazz,constructor,构造函数的参数)生成对象.
javaObj = env->NewObject(clazz,constructor,mainActivity);//mainActivity就是传过去的参数
//查找函数 public String show(int aID,String aName) //5,找 public String show(int aID,String aName)
show = env->GetMethodID(clazz,"show","(ILjava/lang/String;)Ljava/lang/String;");
if (env->ExceptionCheck() ) {
return env->NewStringUTF("show(String aName) not found \n");
}
//6,构造传递的参数int id和String aName
int aID = ; //6.1,手动构造一个数组,为手动构造String准备
jbyteArray data = env->NewByteArray();
jbyte bytes [] = "Lily";
env->SetByteArrayRegion(data,,,bytes); //6.2,手动构String
/*
* 其实可以简单一句就搞定,这里只是为了演示.
* 如: jstring aName = env->NewStringUTF("lucy");
*/
/*
* 手动构String 第1步,找到 class
*/
jclass clz = env->FindClass("java/lang/String");
if (env->ExceptionCheck() ) {
return env->NewStringUTF("java.lang.String not found \n");
}
/*
* 手动构String 第2步,找到 一个构造函数,
* 这里选的是 public String(byte[] data);
* 注意所有类的构造函数(自写的,系统的)名字都只能是 <init>,
* env->GetMethodID(clz,"<init>","XXX");
*/
jmethodID init = env->GetMethodID(clz,"<init>","([B)V");
if (env->ExceptionCheck() ) {
return env->NewStringUTF("<init> exception \n");
}
/*
* 手动构String 第3步,调用构造函数生成对象
* 注意构造函数的参数.要传过去.下面的data就是
*/
jobject stringObject = env->NewObject(clz,init,data); //7,调用show函数,并获取public String show(int aID,String aName) 的返回值
jobject result = env->CallObjectMethod(javaObj,show,aID,stringObject); return (jstring)result;
}
2,数组操作
/*
* Class: com_example_ndksample_MainActivity
* Method: testArrayAll
* Signature: ([B)Ljava/lang/String;
*/
JNIEXPORT void
JNICALL Java_com_example_ndksample_MainActivity_testArrayAll
(JNIEnv *env, jobject mainActivity, jbyteArray javaArray)
{
/*
* 一,jni操作数组的第1对api 访问数组全部数据.
* GetByteArrayElements要与ReleaseByteArrayElements成对出现.在它们之间对数组修改.
* ReleaseByteArrayElements的第三个参数有3个可选值.把副本中的内容更新到源数组,并释放副本.
*/
/*
* ReleaseByteArrayElements第三个参数mode的取值:
0
当isCopy是true时,用这个,说明jvm返回的是数组副本,
把副本的内容更新的源数组,并把副本释放.
JNI_COMMIT
copy back the content but do not free the elems buffer
当isCopy是false时,用这个,说明jvm返回的是数组引用,
这时不要释放数组.
JNI_ABORT
free the buffer without copying back the possible changes
这是只释放掉缓冲,不更新内容
*/ jboolean isCopy;
jint mode = JNI_ABORT;//若是拷贝,只释放副本. //得到javaArray内容,有的jvm是拷贝一份副本,有的jvm是直接引用源数组.看isCopy的返回值.
jbyte *arrayCopy = env->GetByteArrayElements(javaArray,&isCopy);
jint len = env->GetArrayLength(javaArray);
if(isCopy){
//在 拷贝源数组成副本的jvm上运行此代码
mode = ;
}else{
//在 引用源数组的jvm上运行此代码
mode = JNI_COMMIT;
}
//修改数组内容,若isCopy是true,那么修改的是副本,false,修改的是源数组.
for (int i = ; i <= len ; ++ i) {
arrayCopy[i - ] = len - i;
}
//将副本内容更新回java数组中.
env->ReleaseByteArrayElements(javaArray,arrayCopy,mode);
} /*
* Class: com_example_ndksample_MainActivity
* Method: testArrayRegion
* Signature: ([B)Ljava/lang/String;
*/
JNIEXPORT void
JNICALL Java_com_example_ndksample_MainActivity_testArrayRegion
(JNIEnv *env, jobject mainActivity, jbyteArray javaArray)
{
/*
* 二,jni操作数组的第2对api 只拷贝数组中一段范围到目标buf中.
*
* SetByteArrayRegion与GetByteArrayRegion
*
*/
//1,准备缓冲,用来存放拷贝出来的一段副本.
jbyte *buf = new jbyte[];
//2,设定拷贝的范围区域
jint region = ;//只对中间下标为[3,4,5,6,7]这5个感兴趣.
env->GetByteArrayRegion(javaArray,,region,buf);
//3,修改这段区域副本.
for (jint i = ; i < region; ++i) {
buf[i] = '-';
}
//4,更新这段副本内容到源数组.
env->SetByteArrayRegion(javaArray,,region,buf); //5,删除存副本的缓冲区.
delete buf;
}
3, 使用STL
/*
* Class: com_example_ndksample_MainActivity
* Method: testSTL
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_ndksample_MainActivity_testSTL
(JNIEnv *env, jobject mainActivity)
{
/*
* test vector
*/
string result;
vector<int> v;
for (int i = ; i < ; ++i) {
v.push_back(i);
}
result.append("vector<int> :");
for (int i = ; i < v.size(); ++i) {
char b[] = {'\0'};
sprintf(b,"%d",v.at(i));
result.append(b);
result.append(",");
}
result.append("\n");
/*
* test map
*/
map<int,string> mp;
mp.insert(make_pair(,"hell"));
mp.insert(make_pair(,"lili"));
mp.insert(make_pair(,"lucy")); map<int,string>::iterator it;
result.append("map<int,string> :");
for (it = mp.begin(); it != mp.end(); ++it) {
pair<int,string> p = *it;
char key[] = {'\0'};
sprintf(key,"%d",p.first);
result.append(key);
result.append(",");
result.append(p.second.c_str());
result.append(" ");
}
result.append("\n"); return env->NewStringUTF(result.c_str());
}
4,NDK访问设备
/*
* Class: com_example_ndksample_MainActivity
* Method: ndkAccessDevGraphicsF0
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_com_example_ndksample_MainActivity_ndkAccessDevGraphicsF0(
JNIEnv *env, jobject mainActivity)
{
FILE * device;
device = fopen("/dev/graphics/fb0", "r");
if (!device) {
__android_log_print(ANDROID_LOG_ERROR, __func__,"device open field \n");
return;
}
FILE *fp;
fp = fopen("/sdcard/fb0data","w");
if (!fp) {
__android_log_print(ANDROID_LOG_ERROR, __func__,"save file open field \n");
return;
}
char ch ;
while((ch = fgetc(device) ) != EOF){
fputc(ch,fp);
}
fclose(fp);
fclose(device);
}
二、准备java层的相关类.
JavaSchool.java
1 import android.content.Context;
2 import android.util.Log;
3 import android.widget.Toast;
4
5 public class JavaSchool {
6 private int id;
7 private String name;
8 private Context context;
9
10 //没有参数的.
11 public void show(){
12 Log.e("JavaSchool", String.format("id = %d name = ,%s", id,name));
13 }
14 public JavaSchool(){
15 this.id = 0;
16 this.name = "default";
17 }
18 //有参数的
19 public String show(int aID,String aName){
20 this.id = aID;
21 this.name = aName;
22 MainActivity ma = (MainActivity) context;
23 String result = String.format("id = %d name = %s MainActivity.id = %d", id,name,ma.contextId);
24 Log.e("JavaSchool",result );
25 Toast.makeText(context,result, Toast.LENGTH_LONG).show();
26 return result;
27 }
28 public JavaSchool(Context context){
29 this.context = context;
30 this.id = 0;
31 this.name = "default";
32 }
33 }
NativeStudent.java
1 public class NativeStudent {
2 //ndk编程第2步,在java中声明方法.
3 public native String getName();
4 public native static String getCls();
5 public native int add(int x,int y);
6 }
NativeTeacher.java
1 public class NativeTeacher {
2 //ndk编程第2步,在java中声明方法.
3 public native String say();
4 public native static String getName();
5 public native int getAge();
6 public native void setStudent(NativeStudent stu[]);
7 }
NdkCallJava.java
1 public class NdkCallJava {
2 //虽然它在java中是private,在NDK中一样访问
3 private static int age = 18;
4 private String name = "java";
5
6 //static 注意它是private的
7 private static void ageFromNdkStatic(int ageFromNdk){
8 age = ageFromNdk;
9 }
10 public static int getAgeStatic(){
11 return age;
12 }
13 //normal
14 public void ageFromNdk(int ageFromNdk){
15 age = ageFromNdk;
16 }
17 //注意它是private的
18 private void nameFromNdk(String name){
19 this.name = name;
20 }
21
22 //下面两个函数只是为了调用
23 public native String ndkCallJavaField();
24
25 public native String ndkCallJavaMethod();
26 }
MainActivity.java
1 import android.app.Activity;
2 import android.os.Bundle;
3 import android.view.View;
4 import android.widget.TextView;
5
6 public class MainActivity extends Activity {
7
8 public int contextId = 100;//这个数据是在javaSchool中测试MainActivity是否传递成功
9
10 TextView output;
11 byte bytes[];
12
13 //ndk编程第4步,load libNdkSample.so 它在Android.mk中指定的
14 /*
15 * LOCAL_MODULE := NdkSample
16 */
17 static{
18 System.loadLibrary("NdkSample");
19 }
20 //下面是本地函数
21 public native String ndkFindJavaClass();
22 public native void ndkAccessDevGraphicsF0();
23 public native String testClassAndMethod();
24 public native String testSTL();
25 public native void testArrayAll(byte bytes[]);
26 public native void testArrayRegion(byte bytes[]);
27
28 public void onClickTestSTL(View btn){
29 String ret = testSTL();
30 output.append(ret + "\n");
31 }
32 public void init(){
33 bytes = new byte[16];
34 for (byte i = 0; i < bytes.length; i++) {
35 bytes[i] = i;
36 }
37 }
38 public void onClickTestArrayRegion(View btn){
39 output.append("被ndk修改前:");
40 for (int i = 0; i < bytes.length; i++) {
41 output.append(bytes[i] + ",");
42 }
43 testArrayRegion(bytes);
44 output.append("\n被ndk修改后:");
45 for (int i = 0; i < bytes.length; i++) {
46 output.append(bytes[i] + ",");
47 }
48 }
49 public void onClickTestArrayAll(View btn){
50 bytes = new byte[16];
51 for (byte i = 0; i < bytes.length; i++) {
52 bytes[i] = i;
53 }
54 output.append("被ndk修改前:");
55 for (int i = 0; i < bytes.length; i++) {
56 output.append(bytes[i] + ",");
57 }
58 testArrayAll(bytes);
59 output.append("\n被ndk修改后:");
60 for (int i = 0; i < bytes.length; i++) {
61 output.append(bytes[i] + ",");
62 }
63 }
64 public void onClickTestClassAndMethod(View btn){
65 String ret = testClassAndMethod();
66 output.append(ret + "\n");
67 }
68 public void onClickAccessDevGraphicsF0(View btn){
69 ndkAccessDevGraphicsF0();
70 }
71
72 public void onClickNdkCallJavaField(View btn){
73 NdkCallJava ncj = new NdkCallJava();
74 String result = ncj.ndkCallJavaField();
75 output.append(result) ;
76 }
77 public void onClickNdkFindJavaClass(View btn){
78 String ret = ndkFindJavaClass();
79 output.append(ret);
80 }
81 public void onClickNdkCallJavaMethod(View btn){
82 NdkCallJava ncj = new NdkCallJava();
83 String ret = ncj.ndkCallJavaMethod();
84 output.append(ret);
85 }
86 public void onClickNativeTeacherSay(View btn){
87 NativeTeacher t = new NativeTeacher();
88 output.append(t.say());
89 }
90 public void onClickNativeStudentClassName(View btn){
91 output.append(NativeStudent.getCls());
92 }
93
94 @Override
95 protected void onCreate(Bundle savedInstanceState) {
96 super.onCreate(savedInstanceState);
97 setContentView(R.layout.activity_main);
98 output = (TextView) findViewById(R.id.tv_output);
99
100 init();
101 }
102 }
NDK(19)简单示例:ndk调用java基本方法、数组;使用stl、访问设备的更多相关文章
- PySpark 的背后原理--在Driver端,通过Py4j实现在Python中调用Java的方法.pyspark.executor 端一个Executor上同时运行多少个Task,就会有多少个对应的pyspark.worker进程。
PySpark 的背后原理 Spark主要是由Scala语言开发,为了方便和其他系统集成而不引入scala相关依赖,部分实现使用Java语言开发,例如External Shuffle Service等 ...
- 在ASP.Net环境中,当用户点击报表中的超链接时如何调用Java Script方法?
问题描述:在ASP.Net环境中,当用户点击报表中的超链接时如何调用Java Script方法? 问题解答: 你可以在TextObject.Hyperlink对象中编写js代码(javascript: ...
- 在linux下sh批处理文件调用java的方法
解密 java -classpath collection-impl-0.0.1.jar com.ai.toptea.collection.message.DESEncrypt 1EFE4663895 ...
- Android-WebView与本地HTML (HTML调用-->Java的方法)
上一篇博客 Android-WebView加载网络图片&网页 介绍了 使用WebView去加载网络上的图片与网页; 此篇博客专门介绍 Android-WebView与本地HTML (HTML调 ...
- C通过JNI反向调用JAVA程序方法
JNI反向调用JAVA程序 引述:上文讲过java线程---OS线程的关系,然后C怎样反向调用JAVA程序方法是我们这篇讲的重点 1.ThreadTest中添加run()方法 2.编译ThreadTe ...
- 在NDK C++线程中如何调用JAVA API
from://http://www.eoeandroid.com/thread-150995-1-1.html 在NDK中创建的线程中, 只允许调用静态的Java API. 当在线程中调用env-&g ...
- JNI系列——C文件中的方法调用Java中方法
1.创建xxx.jni包并在该包下实现一些Java的方法,和要调用的本地方法 2.实现MainActivity中的按钮点击事件-即点击按钮调用本地的方法 3.在C文件中的方法中回调Java的方法 3. ...
- 分享调用Java private方法
上周在修复bug时,发现Java类中某方法是private,且类中没有用到,第一感觉是方法多余.其实通过分析,发现原来Native Code会通过JNI调到此方法.这也给自己启发,平时做Code re ...
- WebView js 调用Java本地方法
webView = (WebView) this.findViewById(R.id.webview); WebSettings webSettings = webView.getSettings() ...
随机推荐
- 敏捷开发之道(三)极限编程XP续
上次的博文敏捷开发之道(二)极限编程XP中,我们了解了XP的实践中的其中四个,今天我们来一起学习一下剩余的实践. --接上文 5).结对编程 结对编程就是由结对的开发人员使用同一台电脑共同完成一项任务 ...
- BitmapSource ConvertTo Bitmap
偶遇需要把 BitmapSource 转成 Bitmap. .. using System; using System.Drawing; using System.Drawing.Imaging; u ...
- WPF 多线程处理(5)
WPF 多线程处理(1) WPF 多线程处理(2) WPF 多线程处理(3) WPF 多线程处理(4) WPF 多线程处理(5) WPF 多线程处理(6) 项目的目录: 以下是FileStroage的 ...
- ruby 格式化当前日期时间
ruby 格式化当前日期时间 ruby 用Time类获取当前时间. t = Time.new puts t 可以看到输出的是(我现在运行的时间): Sat Jan 29 10:45:22 +0800 ...
- 在云服务器搭建WordPress博客(四)WordPress的基本设置
前面说了 如何安装WordPress,接下来我们需要快速熟悉WordPress,以及进行一些必要的基本设置. 开始设置之前,建议大家先点击一篇左边菜单栏的每一个选项,看看到底是做什么用的.下面开始说一 ...
- 为什么使用long声明和double声明得到的结果不一样呢?
为什么使用long声明和double声明得到的结果不一样呢? 程序如下: public class P376{ public static void main(String[] atgs){ long ...
- 在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3
// test14.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include< ...
- 让你网页同时兼容FireFox和IE
CSS 兼容要点:DOCTYPE 影响 CSS 处理 FireFox: div 设置 margin-left, margin-right 为 auto 时已经居中, IE 不行. FireFox: b ...
- 设计模式之原型模式(prototype)
原理:拷贝自身对象实际上就是调用的拷贝构造函数,注意事项是这里的拷贝是深拷贝,即需要拷贝指针所指的内容 #include <stdio.h> #include <memory> ...
- Matlab中cell2mat的使用
binIndices是1*50的cell,每个cell是的1*n(n不定),那么cell2mat(binIndices)得到的是1*sum(cellfun(@length,binIndices))的行 ...