JNI 提示
1.常规提示
尽量减少 JNI 层的占用空间。
尽可能减少跨 JNI 层编组资源的次数
尽可能避免在使用受管理编程语言编写的代码与使用 C++ 编写的代码之间进行异步通信
尽可能减少需要接触 JNI 或被 JNI 接触的线程数
将接口代码保存在少量易于识别的 C++ 和 Java 源位置,以便将来进行重构
受管理代码:使用 Java 或 Kotlin 编程语言编写
原生代码:使用 C/C++ 编写
2.JavaVM 和 JNIEnv
JNI 定义了两个关键数据结构,两者本质上都是指向函数表的二级指针
JavaVM 提供“调用接口”函数,您可以利用此类来函数创建和销毁 JavaVM
JNIEnv 提供了大部分 JNI 函数。您的原生函数都会收到 JNIEnv 作为第一个参数。
3.线程
最好使用 Thread.start() 创建需要调用 Java 代码的任何线程
这样做可以确保您有足够的堆栈空间、属于正确的 ThreadGroup 且与您的 Java 代码使用相同的 ClassLoader
4.jclass、jmethodID 和 jfieldID
原生代码访问对象的字段的步骤:
使用 FindClass 获取类的类对象引用
使用 GetFieldID 获取字段的字段 ID
使用适当函数获取字段的内容,例如 GetIntField
原生代码访问对象的方法的步骤:
使用 FindClass 获取类的类对象引用
使用 GetMethodID 获取对象的方法 ID
使用适当函数调用方法,例如 CallLongMethod
jclass 是类引用,必须通过调用 NewGlobalRef 来保护它
5.局部引用和全局引用
传递给原生方法的每个参数,以及 JNI 函数返回的几乎每个对象都属于“局部引用”。
局部引用在当前线程中的当前原生方法运行期间有效
获取非局部引用的唯一方法是通过 NewGlobalRef 和 NewWeakGlobalRef 函数。
6.UTF-8 和 UTF-16 字符串
Java 编程语言使用的是 UTF-16
不要忘记 Release 您 Get 的字符串
传递给 NewStringUTF 的数据必须采用修改后的 UTF-8 格式
7.原始数组
JNI 提供访问数组对象内容的函数
8.区域调用
第二种写法具有诸多优势:
需要一个 JNI 调用而不是两个,从而减少开销。
不需要固定或额外复制数据。
降低程序员出错风险,因为不存在操作失败后忘记调用 Release 的风险。
9.异常
在异常挂起时,不得调用大多数 JNI 函数
10.扩展的检查
Android 还提供了一种名为 CheckJNI 的模式,其中 JavaVM 和 JNIEnv 函数表指针已切换为在调用标准实现之前执行一系列扩展的检查的函数表。
11.原生库
您可以使用标准 System.loadLibrary 从共享库加载原生代码。
12.64 位注意事项
为了支持使用 64 位指针的架构,在 Java 字段中存储指向原生结构的指针时,请使用 long 字段而不是 int
13.不支持的功能/向后兼容性
14.常见问题解答:为什么我会收到 UnsatisfiedLinkError?
15.常见问题解答:为什么 FindClass 找不到我的类?
16.常见问题解答:如何使用原生代码共享原始数据?
版权声明: 本文为 InfoQ 作者【Changing Lin】的原创文章。
原文链接:【http://xie.infoq.cn/article/fbcec61452cfaac8698f2a67d】。文章转载请联系作者。
评论