NDK(19)简单示例:ndk调用java基本方法、数组;使用stl、访问设备

一、ndk调用java类示例

1,调用基本方法

 1 /*
 2  * Class:     com_example_ndksample_MainActivity
 3  * Method:    ndkFindJavaClass
 4  * Signature: ()Ljava/lang/String;
 5  */
 6 /*
 7  *     ndk主动查找java类并调用.
 8  */
 9 JNIEXPORT jstring JNICALL Java_com_example_ndksample_MainActivity_ndkFindJavaClass
10   (JNIEnv *env, jobject mainActivity)
11 {
12     jint age ;
13     jfieldID field;
14     jmethodID mid;
15 
16     //1,找到java中相关的类,
17     //用全类名找,包名中的.改成/ 如com/example/ndksample/NdkCallJava
18     jclass cls = env->FindClass("com/example/ndksample/NdkCallJava");
19     if (env->ExceptionCheck() ) {
20         return env->NewStringUTF("NdkCallJava not found \n");
21     }
22     //2,在相关类中找到field
23 
24     field = env->GetStaticFieldID(cls, "age", "I");
25     if (env->ExceptionCheck() ) {
26         return env->NewStringUTF("age not found \n");
27     }
28     //3,用field访问该属性
29     age = env->GetStaticIntField(cls,field);
30 
31     //如果不是静态属性直接用env->GetIntField(jobject obj, jfieldID fieldID);
32     __android_log_print(ANDROID_LOG_ERROR, __func__,"age = %d\n", age);
33 
34     //4,找到java 中的方法
35     /*
36      * 找到public void ageFromNdk(int ageFromNdk)后会调用失败,因为它是非静态的.
37      * 非静态成员要用jobject调用,同时这个对象没有从java中传来,所以这里不能正常调用,
38      * 只能用jclass调用静态的 public void ageFromNdkStatic(int ageFromNdk);
39      * 可以用env new一个类型为"com/example/ndksample/NdkCallJava"的jobject,
40      * 但这个 jobject只是ndk中的并不是java中的,用它调用了也不是所期待的那个.
41      */
42     const char * method = "ageFromNdkStatic"; //它虽然是个private的,但可调用
43     mid = env->GetStaticMethodID(cls, method, "(I)V");
44     if (env->ExceptionCheck() ) {
45         __android_log_print(ANDROID_LOG_ERROR, __func__,"%s not found\n",method);
46         return env->NewStringUTF("ageFromNdkStatic not found \n");
47     }
48     //5,调用java中的静态方法
49     int newAge = 21;//这个是传给 ageFromNdkStatic(int ageFromNdk) 的参数
50     env->CallStaticVoidMethod(cls,mid,newAge);
51     age = env->GetStaticIntField(cls,field);//重新取age的值
52 
53     //6,返回的结果
54     char result[64]={0};
55     sprintf(result,"%s : %d\n","ndkFindJavaClass",age);
56     return env->NewStringUTF(result);
57 }

 

 1 /*
 2  * Class:     com_example_ndksample_MainActivity
 3  * Method:    testClassAndMethod
 4  * Signature: ()Ljava/lang/String;
 5  */
 6 JNIEXPORT jstring JNICALL Java_com_example_ndksample_MainActivity_testClassAndMethod
 7   (JNIEnv *env, jobject mainActivity)
 8 {
 9     /*
10      * 注意函数参数的传递及如何保存java函数返回值,
11      */
12     jclass clazz ;
13     jobject javaObj;
14     jmethodID constructor;
15     jmethodID show ;
16     //1,构造对象第1步: 找到相关class
17     clazz = env->FindClass("com/example/ndksample/JavaSchool");
18     if (env->ExceptionCheck() ) {
19         return env->NewStringUTF("find class exception \n");
20     }
21     //2,构造对象第2步: 选定class中的一个构造函数
22     /*
23      * public JavaSchool(Context context)
24      * 所有类的构造函数名只能是<init>
25      */
26     constructor = env->GetMethodID(clazz,"<init>","(Landroid/content/Context;)V");
27     if (env->ExceptionCheck() ) {
28         return env->NewStringUTF("method <init> exception \n");
29     }
30     //3,构造对象第3步: 为构造函数准备参数 Context context,,这里mainActivity就是
31     //4,构造对象第4步: env->NewObject(clazz,constructor,构造函数的参数)生成对象.
32     javaObj = env->NewObject(clazz,constructor,mainActivity);//mainActivity就是传过去的参数
33     //查找函数 public String show(int aID,String aName)
34 
35     //5,找 public String show(int aID,String aName)
36     show = env->GetMethodID(clazz,"show","(ILjava/lang/String;)Ljava/lang/String;");
37     if (env->ExceptionCheck() ) {
38         return env->NewStringUTF("show(String aName) not found \n");
39     }
40     //6,构造传递的参数int id和String aName
41     int aID = 69;
42 
43     //6.1,手动构造一个数组,为手动构造String准备
44     jbyteArray data = env->NewByteArray(8);
45     jbyte bytes [8] = "Lily";
46     env->SetByteArrayRegion(data,0,8,bytes);
47 
48     //6.2,手动构String
49     /*
50      * 其实可以简单一句就搞定,这里只是为了演示.
51      * 如: jstring aName = env->NewStringUTF("lucy");
52      */
53     /*
54      * 手动构String 第1步,找到 class
55      */
56     jclass clz = env->FindClass("java/lang/String");
57     if (env->ExceptionCheck() ) {
58         return env->NewStringUTF("java.lang.String not found \n");
59     }
60     /*
61      * 手动构String 第2步,找到 一个构造函数,
62      * 这里选的是 public String(byte[] data);
63      * 注意所有类的构造函数(自写的,系统的)名字都只能是 <init>,
64      * env->GetMethodID(clz,"<init>","XXX");
65      */
66     jmethodID init = env->GetMethodID(clz,"<init>","([B)V");
67     if (env->ExceptionCheck() ) {
68         return env->NewStringUTF("<init> exception \n");
69     }
70     /*
71      * 手动构String 第3步,调用构造函数生成对象
72      * 注意构造函数的参数.要传过去.下面的data就是
73      */
74     jobject stringObject = env->NewObject(clz,init,data);
75 
76     //7,调用show函数,并获取public String show(int aID,String aName) 的返回值
77     jobject result = env->CallObjectMethod(javaObj,show,aID,stringObject);
78 
79     return (jstring)result;
80 }

 

2,数组操作

 1 /*
 2  * Class:     com_example_ndksample_MainActivity
 3  * Method:    testArrayAll
 4  * Signature: ([B)Ljava/lang/String;
 5  */
 6 JNIEXPORT void
 7 JNICALL Java_com_example_ndksample_MainActivity_testArrayAll
 8   (JNIEnv *env, jobject mainActivity, jbyteArray javaArray)
 9 {
10     /*
11      * 一,jni操作数组的第1对api 访问数组全部数据.
12      * GetByteArrayElements要与ReleaseByteArrayElements成对出现.在它们之间对数组修改.
13      * ReleaseByteArrayElements的第三个参数有3个可选值.把副本中的内容更新到源数组,并释放副本.
14      */
15     /*
16      *    ReleaseByteArrayElements第三个参数mode的取值:
17         0
18             当isCopy是true时,用这个,说明jvm返回的是数组副本,
19             把副本的内容更新的源数组,并把副本释放.
20         JNI_COMMIT
21             copy back the content but do not free the elems buffer
22             当isCopy是false时,用这个,说明jvm返回的是数组引用,
23             这时不要释放数组.
24         JNI_ABORT
25             free the buffer without copying back the possible changes
26             这是只释放掉缓冲,不更新内容
27      */
28 
29     jboolean isCopy;
30     jint mode = JNI_ABORT;//若是拷贝,只释放副本.
31 
32     //得到javaArray内容,有的jvm是拷贝一份副本,有的jvm是直接引用源数组.看isCopy的返回值.
33     jbyte *arrayCopy = env->GetByteArrayElements(javaArray,&isCopy);
34     jint len = env->GetArrayLength(javaArray);
35     if(isCopy){
36         //在 拷贝源数组成副本的jvm上运行此代码
37         mode = 0;
38     }else{
39         //在 引用源数组的jvm上运行此代码
40         mode = JNI_COMMIT;
41     }
42     //修改数组内容,若isCopy是true,那么修改的是副本,false,修改的是源数组.
43     for (int i = 1;  i <= len ; ++ i) {
44         arrayCopy[i - 1] = len - i;
45     }
46     //将副本内容更新回java数组中.
47     env->ReleaseByteArrayElements(javaArray,arrayCopy,mode);
48 }
49 
50 /*
51  * Class:     com_example_ndksample_MainActivity
52  * Method:    testArrayRegion
53  * Signature: ([B)Ljava/lang/String;
54  */
55 JNIEXPORT void
56 JNICALL Java_com_example_ndksample_MainActivity_testArrayRegion
57   (JNIEnv *env, jobject mainActivity, jbyteArray javaArray)
58 {
59     /*
60      * 二,jni操作数组的第2对api  只拷贝数组中一段范围到目标buf中.
61      *
62      *    SetByteArrayRegion与GetByteArrayRegion
63      *
64      */
65     //1,准备缓冲,用来存放拷贝出来的一段副本.
66     jbyte *buf = new jbyte[16];
67     //2,设定拷贝的范围区域
68     jint region = 5;//只对中间下标为[3,4,5,6,7]这5个感兴趣.
69     env->GetByteArrayRegion(javaArray,3,region,buf);
70     //3,修改这段区域副本.
71     for (jint i = 0; i < region; ++i) {
72         buf[i] = '-';
73     }
74     //4,更新这段副本内容到源数组.
75     env->SetByteArrayRegion(javaArray,3,region,buf);
76 
77     //5,删除存副本的缓冲区.
78     delete buf;
79 }

 

3, 使用STL

 1 /*
 2  * Class:     com_example_ndksample_MainActivity
 3  * Method:    testSTL
 4  * Signature: ()Ljava/lang/String;
 5  */
 6 JNIEXPORT jstring JNICALL Java_com_example_ndksample_MainActivity_testSTL
 7   (JNIEnv *env, jobject mainActivity)
 8 {
 9     /*
10      * test vector
11      */
12     string result;
13     vector<int> v;
14     for (int i = 0; i < 16; ++i) {
15         v.push_back(i);
16     }
17     result.append("vector<int> :");
18     for (int i = 0; i < v.size(); ++i) {
19         char b[3] = {'\0'};
20         sprintf(b,"%d",v.at(i));
21         result.append(b);
22         result.append(",");
23     }
24     result.append("\n");
25     /*
26      * test map
27      */
28     map<int,string> mp;
29     mp.insert(make_pair(0,"hell"));
30     mp.insert(make_pair(1,"lili"));
31     mp.insert(make_pair(2,"lucy"));
32 
33     map<int,string>::iterator it;
34     result.append("map<int,string> :");
35     for (it = mp.begin(); it != mp.end(); ++it) {
36         pair<int,string> p = *it;
37         char key[3] = {'\0'};
38         sprintf(key,"%d",p.first);
39         result.append(key);
40         result.append(",");
41         result.append(p.second.c_str());
42         result.append(" ");
43     }
44     result.append("\n");
45 
46     return env->NewStringUTF(result.c_str());
47 }

 

4,NDK访问设备

 1 /*
 2  * Class:     com_example_ndksample_MainActivity
 3  * Method:    ndkAccessDevGraphicsF0
 4  * Signature: ()V
 5  */
 6 JNIEXPORT void JNICALL
 7 Java_com_example_ndksample_MainActivity_ndkAccessDevGraphicsF0(
 8         JNIEnv *env, jobject mainActivity)
 9 {
10     FILE * device;
11     device = fopen("/dev/graphics/fb0", "r");
12     if (!device) {
13         __android_log_print(ANDROID_LOG_ERROR, __func__,"device open field \n");
14         return;
15     }
16     FILE *fp;
17     fp = fopen("/sdcard/fb0data","w");
18     if (!fp) {
19         __android_log_print(ANDROID_LOG_ERROR, __func__,"save file open field \n");
20         return;
21     }
22     char ch ;
23     while((ch = fgetc(device) ) != EOF){
24         fputc(ch,fp);
25     }
26     fclose(fp);
27     fclose(device);
28 }

 

二、准备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 }

 

posted @ 2015-08-22 19:08  f9q  阅读(928)  评论(0编辑  收藏  举报