動態(tài)注冊
在靜態(tài)注冊中,每次添加新函數(shù)后,要重新生成頭文件,而且函數(shù)名較長,操作起來非常麻煩,那使用動態(tài)注冊可以避免這些麻煩 。
而動態(tài)注冊可以避免這些麻煩。 JNI中提供了RegisterNatives方法來注冊函數(shù)
并且我們在調(diào)用 System.loadLibrary的時候,會在C/C++文件中回調(diào)一個名為 JNI_OnLoad 的函數(shù)
在這個函數(shù)中一般是做一些初始化設(shè)定和指定jni版本 我們可以在這個方法里面注冊函數(shù)
現(xiàn)在我們不需要頭文件,只需要 C/C++ 源文件,.mk文件也和靜態(tài)注冊的一樣
// jni頭文件
#include <jni.h>
#include <cassert>
#include <cstdlib>
#include <iostream>
using namespace std;
//native 方法實現(xiàn)
jint get_random_num(){
return rand();
}
/*需要注冊的函數(shù)列表,放在JNINativeMethod 類型的數(shù)組中,
以后如果需要增加函數(shù),只需在這里添加就行了
參數(shù):
1.java代碼中用native關(guān)鍵字聲明的函數(shù)名字符串
2.簽名(傳進來參數(shù)類型和返回值類型的說明)
3.C/C++中對應(yīng)函數(shù)的函數(shù)名(地址)
*/
static JNINativeMethod getMethods[] = {
{"getRandomNum","()I",(void*)get_random_num},
};
//此函數(shù)通過調(diào)用JNI中 RegisterNatives 方法來注冊我們的函數(shù)
static int registerNativeMethods(JNIEnv* env, const char* className,JNINativeMethod* getMethods,int methodsNum){
jclass clazz;
//找到聲明native方法的類
clazz = env->FindClass(className);
if(clazz == NULL){
return JNI_FALSE;
}
//注冊函數(shù) 參數(shù):java類 所要注冊的函數(shù)數(shù)組 注冊函數(shù)的個數(shù)
if(env->RegisterNatives(clazz,getMethods,methodsNum) < 0){
return JNI_FALSE;
}
return JNI_TRUE;
}
static int registerNatives(JNIEnv* env){
//指定類的路徑,通過FindClass 方法來找到對應(yīng)的類
const char* className = "com/example/wenzhe/myjni/JniTest";
return registerNativeMethods(env,className,getMethods, sizeof(getMethods)/ sizeof(getMethods[0]));
}
//回調(diào)函數(shù) 在這里面注冊函數(shù)
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
JNIEnv* env = NULL;
//判斷虛擬機狀態(tài)是否有問題
if(vm->GetEnv((void**)&env,JNI_VERSION_1_6)!= JNI_OK){
return -1;
}
assert(env != NULL);
//開始注冊函數(shù) registerNatives -》registerNativeMethods -》env->RegisterNatives
if(!registerNatives(env)){
return -1;
}
//返回jni 的版本
return JNI_VERSION_1_6;
}
上面的代碼就能實現(xiàn)動態(tài)注冊jni了 以后要增加函數(shù)只需在java文件中聲明native方法,在C/C++文件中實現(xiàn),
并在getMethods數(shù)組添加一個元素并指明對應(yīng)關(guān)系,通過ndk-build 生成so庫就可以運行了
上面代碼中registerNatives()和 registerNativeMethods()方法是我們自己寫的,其實完全可以寫到一個函數(shù)里面
當(dāng)初不懂原理的時候看網(wǎng)上教程以為必須要這么寫,后來懶得改了,直接拿來用了, 而env->RegisterNatives()方法
是jni中提供的,用來注冊我們想要注冊的函數(shù)
參考文章
http://blog.csdn.net/wwj_748/article/details/52347341
http://blog.csdn.net/venusic/article/details/52121254
http://blog.csdn.net/u010925331/article/details/50992505 (很清楚)