細說JNI與NDK專題目錄:
細說JNI與NDK(一) 初體驗
細說JNI與NDK(二)基本操作)
細說JNI與NDK(三)ndk 配置說明
細說JNI與NDK(四)動態(tài)和靜態(tài)注冊
細說JNI與NDK(五)JNI 線程
細說JNI與NDK(六)靜態(tài)緩存儒将,異常捕獲椅您,內(nèi)置函數(shù)
細說JNI與NDK(七)Parcel底層JNI思想與OpenCV簡單對比
Android Framework源代碼中的動態(tài)注冊
靜態(tài)注冊和動態(tài)注冊
靜態(tài)注冊
默認情況下邓深,就是靜態(tài)注冊肄鸽,靜態(tài)注冊是最簡單的方式,NDK開發(fā)過程中酝锅,基本上使用靜態(tài)注冊巧骚。前面的知識都是靜態(tài)注冊的方式吭产。
優(yōu)點:
開發(fā)簡單
缺點:
- JNI函數(shù)名非常長
- 捆綁 上層 包名 + 類名
- 運行期 才會去 匹配JNI函數(shù)个从,性能上 低于 動態(tài)注冊
動態(tài)注冊
再看Android Framework源代碼的Native層拦宣,Android 系統(tǒng)的C++源碼:基本上都是動態(tài)注冊。
動態(tài)注冊是怎么玩轉(zhuǎn)的信姓?
明白一個簡單的道理鸵隧,Java中我們new 類,默認會調(diào)用構(gòu)造函數(shù)意推,重寫了構(gòu)造函數(shù)豆瘫,就會調(diào)用我們自己的。NDK中Jni函數(shù)也是這樣菊值,默認會有JNI_OnLoad 一系列函數(shù)外驱,我們重寫JNI_OnLoad
來加載我們自己的邏輯。
當我們調(diào)用腻窒,System.loadLiberary("xxxxx");
<---->
實際上自動調(diào)用了JNI_OnLoad 做動態(tài)注冊
先看下示例代碼
? Java 部分
public native void dynamicJavaM01();
public native int dynamicJavaM01(String value);
調(diào)用
case R.id.jni_regist_1:
dynamicJavaM01();
break;
case R.id.jni_regist_2:
dynamicJavaM01("JNI動態(tài)注冊昵宇,JNI傳參");
break;
? C++ 部分
#include "include/common_head.h"
//JNIEnv *env, jobject thiz, 默認這兩個參數(shù)是可以省略,如果不用的話
//void dynamicM01(JNIEnv *env, jobject thiz)
void dynamicM01() {
LOGD("我是動態(tài)注冊的函數(shù) dynamicM01...");
}
int dynamicM02(JNIEnv *env, jobject thiz, jstring value) {
const char * text = env->GetStringUTFChars(value, nullptr);
LOGD("我是動態(tài)注冊的函數(shù) dynamicM02...%s",text);
env->ReleaseStringUTFChars(value,text);
return 200;
}
JavaVM *javaVm;
const char *class_name = "top/zcwfeng/jni/JavaJNIActivity";
//name,signature,*
static const JNINativeMethod methods[] = {
{"dynamicJavaM01", "()V", (void *) (dynamicM01)},
{"dynamicJavaM02", "(Ljava/lang/String;)I", (int *) (dynamicM02)},
};
jint JNI_OnLoad(JavaVM *vm, void *unused) {
::javaVm = vm;
JNIEnv *jniEnv = nullptr;
int result = javaVm->GetEnv(reinterpret_cast<void **>(&jniEnv), JNI_VERSION_1_6);
//result 等與0 成功儿子,默認不成文規(guī)則瓦哎,封裝庫都是成功就是0【如ffmpeg庫等】
if (result != JNI_OK) {
return -1;
}
LOGE("System.loadLibrary --->JNI Load init success");
jclass clazz = jniEnv->FindClass(class_name);
//RegisterNatives(jclass clazz, const JNINativeMethod* methods,jint nMethods)
jniEnv->RegisterNatives(clazz, methods,sizeof(methods)/sizeof(JNINativeMethod));
LOGE("動態(tài) 注冊 dynamic success");
return JNI_VERSION_1_6;// AS的JDK在JNI默認最高1.6 Java的JDKJNI 1.8
}
- JNI_OnLoad 中賦值我們用了域的方式,如:this.a = a ---> ::javaVm = vm
- 默認不成文規(guī)則柔逼,C 中封裝庫都是成功就是0
- AS的JDK目前JNI默認最高1.6 和 Java的JDK的JNI 1.8不同
- JNI_OK 就是JNI提供的一些宏定義方便使用蒋譬。
- 動態(tài)注冊的方法參數(shù),JNIEnv *env 和 jobject thiz愉适,如果沒有用到是可以不放到參數(shù)列表中犯助,沒有影像。
- 動態(tài)注冊核心RegisterNatives
① 重寫JNI_OnLoad
② JavaVM 初始化獲取JNIEnv维咸,并獲取到j(luò)class
③ 注冊函數(shù)
//RegisterNatives(jclass clazz, const JNINativeMethod* methods,jint nMethods)
jniEnv->RegisterNatives(clazz, methods,sizeof(methods)/sizeof(JNINativeMethod));
參數(shù)需要提供剂买,所在的類,數(shù)組(包含需要動態(tài)注冊的方法)癌蓖,數(shù)組的大小
小技巧瞬哼,傳入JNINativeMethod* 以為指針相當于我們定義一個數(shù)組