靜態(tài)注冊
原理:根據(jù)函數(shù)名來建立 java 方法與 JNI 函數(shù)的一一對應(yīng)關(guān)系;
實(shí)現(xiàn)流程:
編寫 java 代碼;
利用 javah 指令生成對應(yīng)的 .h 文件;
對 .h 中的聲明進(jìn)行實(shí)現(xiàn);
弊端:
編寫不方便,JNI 方法名字必須遵循規(guī)則且名字很長;
編寫過程步驟多,不方便;
程序運(yùn)行效率低,因?yàn)槌醮握{(diào)用native函數(shù)時(shí)需要根據(jù)根據(jù)函數(shù)名在JNI層中搜索對應(yīng)的本地函數(shù),然后建立對應(yīng)關(guān)系,這個(gè)過程比較耗時(shí);
動(dòng)態(tài)注冊
原理:利用 RegisterNatives 方法來注冊 java 方法與 JNI 函數(shù)的一一對應(yīng)關(guān)系;
實(shí)現(xiàn)流程:
利用結(jié)構(gòu)體 JNINativeMethod 數(shù)組記錄 java 方法與 JNI 函數(shù)的對應(yīng)關(guān)系;
實(shí)現(xiàn) JNI_OnLoad 方法,在加載動(dòng)態(tài)庫后,執(zhí)行動(dòng)態(tài)注冊;
調(diào)用 FindClass 方法,獲取 java 對象;
調(diào)用 RegisterNatives 方法,傳入 java 對象,以及 JNINativeMethod 數(shù)組,以及注冊數(shù)目完成注冊;
動(dòng)態(tài)注冊方式:
1:第一步先實(shí)現(xiàn)JNI_OnLoad方法(利用 RegisterNatives 方法來注冊 java 方法與 JNI 函數(shù)的一一對應(yīng)關(guān)系)
static const char* mClassName="com/demo/jnitest/MainActivity";
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)extern "C" JNIEXPORT jint? JNICALL
JNI_OnLoad(JavaVM *vm,void *reserved){
LOGI("JNI_OnLoad");
? ? _vm=vm;
? ? JNIEnv *jniEnv;
? ? jint r = vm->GetEnv((void**)&jniEnv, JNI_VERSION_1_6);
? ? if (r!=JNI_OK){
return -1;
? ? }
jclass pJclass = jniEnv->FindClass(mClassName);
? ? if(pJclass==NULL){
printf("cannot get class:%s\n", mClassName);
? ? ? ? return -1;
? ? }
//注冊
? ? jniEnv->RegisterNatives(pJclass,getMethod, sizeof(getMethod)/sizeof(JNINativeMethod));
? ? return JNI_VERSION_1_6;
}
2:利用結(jié)構(gòu)體 JNINativeMethod 數(shù)組記錄 java 方法與 JNI 函數(shù)的對應(yīng)關(guān)系
static const JNINativeMethod getMethod[]{
{"javaAdd","(II)I",(jint *)C_Add},
};
其中testThread是在Activity頁面聲明好的native函數(shù)。
public native int javaAdd(int a,int b);
方法初始化調(diào)用:
extern "C" JNIEXPORT jint JNICALL
C_Add(JNIEnv *env,
? ? ? ? jobject jobject1,
? ? ? ? jint a,
? ? ? ? jint b){
return a+b;
}