JNI开发——基本实现

jni 全名是java native interface。

JNI资料

什么时候使用JNI:

       1、 java api 不能满足程序需要的时候

        2、要求性能比较高的时候,算法的计算,图像的渲染等。

        3、当需要访问已有的本地库的时候

开发步骤:

        1、编写native方法。

        2、javah生成 .h 头文件

        3、复制 .h文件到cpp目录。

        4、实现.h头文件中的声明函数。

1、写个hello world:

C代码:

JNI开发——基本实现_第1张图片

java代码:

JNI开发——基本实现_第2张图片

C 中env是一个结构体二级指针。

上面是静态的java方法,现在用一个非静态的方法:

java代码:

JNI开发——基本实现_第3张图片

C代码:

JNI开发——基本实现_第4张图片

静态方法和非静态方法除了调用的时候不一样之外在C代码里面只有jclass和jobject这一个参数的不同。

JNI的基本数据类型:

jboolean、jbyte、jchar、jshort、jint、jlong、jfloat、jdouble

引用类型:字符 jstring  其他都是object;

数组:jByteArray   公式:jTypeArray;

引用类型数组:都是jobjectArray;

java方法的签名

JNI开发——基本实现_第5张图片

如:void a(int b)  签名就是"(I)V"

String gets() 签名是"()Ljava/lang/String;"

其他类型如Bitmap 就是"Ljava/lang/Object"

 对于数组,其为 :  [ + 其类型的域描述符 + ;

                  int[ ]     其描述符为[I

                  float[ ]   其描述符为[F

                  String[ ]  其描述符为[Ljava/lang/String;

                 Object[ ]类型的域描述符为[Ljava/lang/Object;

          多维数组则是 n个[ +该类型的域描述符 , N代表的是几维数组。例如:

             int  [ ][ ] 其描述符为[[I

            float[ ][ ] 其描述符为[[F

2、c访问java中的非静态域:

C的代码:

JNI开发——基本实现_第6张图片

java的代码:

JNI开发——基本实现_第7张图片

显示结果:miK简单的JNI。

错误一:不要直接strcat(text,c_str),因为text有存储“简单JNI”这几个字符的空间,后面拼接的字符存不下,可以使用数组 char[50] text。

错误二的写法:

JNI开发——基本实现_第8张图片

显示结果:miK

new 了一个mainActivity的新对象 修改了这个对象中的key值,并没有修改当前mainactivity中的key值。

3、c访问java中的静态域:

C代码:

JNI开发——基本实现_第9张图片

java 代码:

JNI开发——基本实现_第10张图片

输出结果:11。

也就是C方法上多了一个static。

4、c调用java的非静态方法:

C代码:

JNI开发——基本实现_第11张图片

java代码:

JNI开发——基本实现_第12张图片

输出结果就是随机的整数。

5、c调用java的静态方法:

c代码:

JNI开发——基本实现_第13张图片

java代码:


JNI开发——基本实现_第14张图片

输出结果就是一串字符串。

6、c调用java的构造方法:

c代码:

JNI开发——基本实现_第15张图片

java代码:


JNI开发——基本实现_第16张图片

输出结果:


7、JNI字符串乱码问题:

java使用utf-16的编码方式(16bit),中英文都是用2个字节

jni中使用utf-8的编码方式,英文是一个字节,英文三个字节

C/C++英文使用ASCII编码方式,中文使用GB2312编码方式,两个字节表示一个汉字。

android studio 右下角默认utf-8的编码方式,所以没有EC上的乱码

8、GetStringUTFChars(env, j_str,NULL)第三个参数的问题说明:


JNI开发——基本实现_第17张图片

输出的日志:iscp = JNI_TRUE。所以第三个参数是取值,不是传值。java的string在是否内存中复制了一份给C使用,可以通过这个判断是否回收释放。

9、访问java基本类型的数组:

c代码:

JNI开发——基本实现_第18张图片

java代码:

JNI开发——基本实现_第19张图片

输出结果:

JNI开发——基本实现_第20张图片

10、访问java引用类型数组:

c代码:

JNI开发——基本实现_第21张图片

java代码:

JNI开发——基本实现_第22张图片

输出结果:

11、JNI的引用:

局部引用:

JNI开发——基本实现_第23张图片

全局引用:

JNI开发——基本实现_第24张图片

弱全局引用:

JNI开发——基本实现_第25张图片

12、JNI异常处理:


JNI开发——基本实现_第26张图片

在java中就可以try  catch 捕获了

13、JNI缓存:

局部静态变量缓存:

C代码:

JNI开发——基本实现_第27张图片

java代码:

JNI开发——基本实现_第28张图片

只打印了一次“javaKey”,如果把static去掉就会打印多次。

存储在静态区,只需定义并初始化一次,之后一直有。

全局静态缓存:

JNI开发——基本实现_第29张图片

全局使用这个变量只能在定义之后的方法里使用

14、动态注册:

java代码:

JNI开发——基本实现_第30张图片

FileUtils:

JNI开发——基本实现_第31张图片

C代码:


JNI开发——基本实现_第32张图片


JNI开发——基本实现_第33张图片

JNI_Onload方法由系统调用,具体在哪调用下一篇JNI原理会有。

静态注册:

1、每个class都需要使用javah生成一个头文件,并且生成的名字很长书写不便;

2、初次调用时需要依据名字搜索对应的JNI层函数来建立关联关系,会影响运行效率

3、用javah 生成头文件方便简单

动态注册:

1、使用一种数据结构JNINativeMethod来记录java native函数和JNI函数的对应关系

2、移植方便(一个java文件中有多个native方法,java文件的包名更换后)

你可能感兴趣的:(JNI开发——基本实现)