- target a. 用最通俗的语言来描述JNI 到底是个什么鬼。
- target b. 加载JNI库 , native函数
- target c. 注册JNI函数 (方式与类型
target d. 啥也不说,先上图
a. 如上, 有了JNI层,Java与平台的实现层实现了隔离,这样就可以做到Java与平台的无关性,实现夸平台的兼容性扩展
b. 问题来了,JNI是以何种方式做到中间转化的呢?
莫急,一步步来
b.1 注册 Native方法,即JNI 函数 先将JNI的函数集 封装到JNINativeMethod sMethods 数组里 =
b.2 调用 jniRegisterNativeMethods 注册 上面的sMethods
如以下Bluetooth/btservice/AdapterService为例
b.3 从Native 对接到C层实现会封装在 funcPtr里, 以enableNative 为例
b.4 关于类型标志表 见以下图
以上后面跟的那些奇怪的符号,其实就是参考下面的表,就是那么回事(没有啥高深莫测的……)
b.5 那么Java 是如何调用到JNI?(即访问到 JNI中的函数方法实现)
我相信你们一定知道,C层函数里如何调用标准C库的(通过加载呗,通过访问头文件(include到本地文件里,然后就像自家人想怎么用就怎么用!! ))
Java也是一样, 通过System.loadLibraray() 加载 , 它会进一步调用 JNI_OnLoad(JavaVM *jvm, void *reserved) (该部分是在JVM虚拟机里实现) 加载完了库之后(就像媳妇取过了们后),Java就可以在本地想干啥就干啥(当然要控制度哈。。。。)
可见以下代码
b.6 到里这里总结下, Java为了更好的隔离平台实现呢,自己搞了一层JVM虚拟机(很强大,有一本书专门讲它,但他也是罪魁祸首,Android常见的 性能瓶颈基本在他手上,所谓大内存也是被他吃的光光 。。。。 ) 然后JNI (就上按照上面的一套规则,运行在JVM上),他对接到Native(我们的C/C++),只要Java Load库成功后,就可以在本地像用自家东西一样 调用底层的函数实现方法。
c. 对了, 接着上面再扯扯 JNI内存回收的问题 。每个JNI 都会配对对应
static bool initNative(JNIEnv* env, jobject obj)
static bool cleanupNative(JNIEnv *env, jobject obj)
这两个函数做了啥呢。 前者,申请了NewGlobalRef 全局对象
后者, 释放了DeleteGlobalRef 内存这两部分都会放在 (调用者)Java 类里, 作为一个靠谱的代码狗,一定要在使用了 initNative之后, 记得调用cleanupNative 释放内存否则,你就是在埋坑,坑队友 。。。。。