JNI 笔记
最近在看《深入理解 Android: 卷 I》,Framework 层要和 Native 层打交道,一开始肯定得介绍 JNI;
13 年项目中用到 WebP 的时候虽然接触过 JNI,但没有系统学习过,所以这里算是做个笔记。
JNI方法注册:
静态注册:
对所有声明了 native 方法的 Java 类,运行
javah -o output packageName.className
生成 .h 头文件;生成的 JNI 函数名带有包路径。
动态注册:
通过
JNINativeMethod
结构体定义 Java native 方法和 JNI 中函数的对应关系;调用
AndroidRunTime::registerNativeMethods()
函数完成注册,该函数内部调用(*env)->RegisterNatives()
函数;Java 层调用
System.loadLibrary()
,动态注册自动在JNI_OnLoad()
函数中进行的。
JNINativeMethod类型定义:
typedef struct {
const char* name; //Native函数名,不带包名
const char* signature; //方法签名,格式:“(参数类型1,参数类型2...)返回类型”
void* funcPtr; //JNI层对应的函数指针
} JNINativeMethod;
JNIEnv:
实际上就是封装了一些 JNI 系统函数,通过这些函数可以调用 Java 函数、操作
jobject
对象。它是线程相关的,通过调用 JavaVM 的
AttachCurrentThread()
函数可以得到当前线程的JNIEnv
对象;在后台线程退出前,也需要调用DetachCurrentThread()
函数来释放资源;得到 Java 类、方法、属性:
env->FindClass()
、env->GetMethodID()
、env->GetFieldID()
;调用 Java 方法:
Call<Type>Method()
、CallStatic<Type>Method()
;读取 Java 属性值:
Get<Type>Field()
、Set<Type>Field()
;字符串操作:
创建
jstring
:env->NewString()
、env->NewStringUTF()
;字符操作:
env->GetStringChars()
、env->GetStringUTFChars()
、env->ReleaseStringChars()
、env->ReleaseStringUTFChars()
;
JNI 引用类型:
Local Reference: 一旦 JNI 层函数返回,
jobject
对象就会被回收;Global Reference: 全局(静态)引用,如不调用
env->DeleteGlobalRef()
主动释放,永远不会被回收;Weak Global Reference: 使用前需要调用
env->ISSameObject()
判断是否被回收;
JNI 异常处理:
JNI 层出错不会中断 native 代码运行,直到返回 Java 层后,虚拟机才会抛出异常;
JNI 层出现异常后,需要做资源释放;
JNIEnv
提供的异常处理函数:env->ExceptionOccured()
: 判断是否发生异常;env->ExceptionClear()
: 清理当前 JNI 层中发生的异常;env->ThrowNew()
: 向 Java 层抛出异常;