《深入理解Android》:JNI

JNI层必须实现为动态库,才能被虚拟机加载并调用,一般命名为:lib模块名_jni.so。

JNI的实现有两个点:1、在native方法调用前被加载,一般是在static{}里面使用System.loadLibrary(),动态库名与实际操作的名不一样,因为系统会自动匹配;2、用native声明的函数表示该函数即将会从JNI里完成。(被调用的JNI函数必须先声明,类似C语言)

 

JNI的注册主要是通过方法名字来进行相关联系的,例如如果在android.media.test有一个方法Init(),那么全名就是android.media.test.Init(),在JNI的库函数里,因为“.”有特殊意义所以对应函数名被改为android_media_test_Init().

这里有两张注册方法,一种是静态注册:其实就是“JAVAC之后JAVAH”,当用户在JAVA层执行某native方法的时候,就会根据当前包名和方法名在库里找相应的函数,并且为JAVA层的方法和JNI层的方法做一个关系链接。另外一种是动态注册:在知道JAVA层与JNI之间使用指针进行链接之后,我们只要操控好指针结构即可,最终会在JNIEnv的方法里进行注册,进行动态注册要明白,当JAVA层loadLibrary之后就会在库里寻找并执行onload方法,一般就在这里进行注册。

 

当然既然是JAVA与C++,那么就涉及到了类型转换详细的列表不说,不过值得注意的是,除了少数的类型之外,几乎所有的类在JNI里面都表示成jObject。那么如何操控jobject?首先需要引入JNIEnv。

JNIEnv:

它与线程相关因此每个线程都有相应的JNIEnv实例,由图可见,它与提供函数这件事情密切相关。它可从虚拟机实例获得当前线程的JNIEnv。JNIEnv的作用书里用一个JNI调用JAVA层函数的例子来说明,其实有点类似映射,先通过一定的方法获取jfiledID和jmethodsID,然后后面通过CALL方法来调用JAVA层方法并获取数据。

 

接下来还是要讲一下,在动态注册的结构体中有一个签名。它之所以存在是因为JAVA有重载,因此仅仅通过名字是无法一一对应的,就需要返回类型、参数类型来进行签名。

 

JAVA的垃圾回收机制同样会影响JNI,因此在JNI层,默认的非全局引用变量都是local reference,虽然一旦JNI函数返回它就可能会被回收,但是一般还是会释放引用的。此外还有global reference以及,weak global reference,前者不手动释放的话就永远不会被回收,后者其实就是弱引用。

 

待续.

posted @ 2013-12-11 20:56  yutoulck  阅读(292)  评论(0编辑  收藏  举报