JNI在Android和c/c++中起着重要的作用,就相当于桥梁。你知道抗日时候为啥要先炸桥梁就知道JNI在其中的重要性了。
JNI是Java Native interface的缩写。JNI不是安卓特有的,是从Java继承过来的,但是在Android中,JNI的作用大大增强了。就好比火药是中国发明的,外国继承了火药发明了导弹一样。 Android作为嵌入式操作系统,有大量和驱动,硬件有关的功能必须在native实现,另外一些注重性能,功耗的功能用c/c++也要优于java。 在Android中,java主要负责UI功能的实现,而c/c++则负责完成一些复杂的算法及底层的交互功能,因此Android中java和c/c++交互特别的频繁。所以有的人说android开发就是做java的,真的是很可怕的想法。 无论Java到c/c++,还是c/c++到java 中间都没有跨线程调用,两者在一个线程中,只是两者的线程id表示不同而已。java层的线程id从1开始,c/c++层实用的是一个与线程相关的数据结构的指针,两者不能比较。
1. 装载JNI动态链接库 为了使JNI在本地方法调用前吧c/c++代码所在动态库装载待进程的内存空间中,装载库文件调用的是System的LoadLibrary()方法。
static {
System.loadLibrary("MyJni");
}
这里出入的参数只是动态库的文件名一部分。 Android JNI动态库的名称必须以”lib”开头, 这里传入的参数去掉了前缀”lib”和”.so”的中间部分。
2.定义native方法 在java类中定义narive方法很简单,在前面加上“native”关键字就行了,
public static native String getStringFromNative();
3.编写JNI动态库 JNI动态库和非动态库区别:JNI动态库中定义了一个名为“JNI OnLoader”的函数,这个函数在动态库加载后被系统调用,用于完成JNI函数的注册。在JNI_OnLoader函数中,最重要的一件事就是调用registerNativeMethods ()函数完成动态库中JNI函数的注册,所谓注册,就是通过一张表把java类中定义的native方法和本地C函数联系起来,这样Dalvik虚拟机在解析java类中的native方法是境内查找到对应的C函数 4.参数签名 为什么会有方法签名这种东西呢?这是因为Java这边支持函数重载,即虽然参数不一样,但是方法名一样,那么在JNI层它们的方法名都会是一样的,那JNI也会犯迷糊了,得找哪个呢? 不过也正是因为其参数类型是不一样的,所以就出现了方法签名,利用方法签名和方法名来唯一确定一个JNI函数的调用。
typedef union jvalue {
jboolean z;
jbyte b;
jchar c;
jshort s;
jint i;
jlong j;
jfloat f;
jdouble d;
jobject l;
} jvalue;
签名由参数和返回值组成: 例如: (I)V 表示 有一个整型参数,无返回值 (IZ)I 表示 两个参数,第一个整型,第二个布尔型,返回整型
图解签名:
5.如何使用JNI类型 在JNI中,提供了以下各种数据类型,可以分为原生类型和引用类型: 对于原生类型有:jchar, jbyte, jshort, jint, jlong, jfloat, jdouble, jboolean,其与java端的数据类型对应如下表:
Tables | Are |
---|---|
java | jni |
char | jchar |
byte | jbyte |
short | jshort |
int | jint |
long | jlong |
float jfloat | |
double jdouble | |
boolean | jboolean |
ART中的垃圾回收算法将回移动对象在内存中的位置。这样目的是为了减少内存碎片,提高内存使用率。这会java没太大影响,但是对JNI就要注意,不要试图通过指针方式直接访问函数分配的对象。
我们知道JNI使用和释放java层传递的数组参数要通过Get..ArratElement()
和 Release…ArratElement()
两组函数完成的。在Dalivk中,Get..ArratElement()
函数返回的是数组元素实际的内存引用,但是在ART中,这个函数返回的是数组元素的复制。
ART中JNI函数会抛出“异常”,而Dalivk中之时返回NULL。
在Dalivk中,java和native代码使用的不同的堆栈,大小也不同,java大小32kb,native大小1MB。 在ART中,native带啊使用相同的堆栈。 在Java代码中,Thread类的构造方法可以制定堆栈的大小。