靜態註冊:
在JNI中,一般的流程是先寫一個native方法,然後通過javah命令生成頭文件,然後拷貝頭文件中對應的方法,寫具體的邏輯。
package com.soft.lpf;
public class LiveUtils{
public static native void live(String p, String patt_P, int num);
static {
System.loadLibrary("native-lib");
}
}
通過javah命令生成的頭文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_administrator_dnndkfilesplit_FileUtils */
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_administrator_dnndkfilesplit_FileUtils
* Method: diff
* Signature: (Ljava/lang/String;Ljava/lang/String;I)V
*/
JNIEXPORT void JNICALL Java_com_soft_lpf_FileUtils_live
(JNIEnv *, jclass, jstring, jstring, jint);
#ifdef __cplusplus
}
#endif
#endif
這樣就可以只用頭文件中的live方法了,但是,靜態註冊存在幾個明顯的不足之處:
1.JNI層的方法名字過程,統稱會包含java層的包全路徑以及其他的字符。
2.聲明native類,需要用到javah命令生成的頭文件,這樣就會造成不必要的麻煩。
3.初次調用的時候,需要先創建關聯,效率不高。
4.具有一定的耦合性,不利於移植重複應用。
靜態註冊,就是native的java方法就是通過方法指針來跟JNI層進行關聯的,如果知道native方法在JNI層對應的指針,這就避免了上面的問題,這就是動態註冊。
動態註冊:
在JNI中是通過結構體來對native方法和jni方法進行關聯的,它就是JNINativeMethod,這個結構體在jni.h中被定義了。
typedef struct {
const char* name; //java方法名
const char* signature; //java方法的簽名信息
void* fnPtr; //jni方法指針
} JNINativeMethod;
這樣便可以依照源碼,自己定義一個方法數組
static const JNINativeMethod gMethods[]={
{"live","(Ljava/lang/String;Ljava/lang/String;I)V",(void*)native_live}
};
如果有多個native方法需要動態註冊,只需要在這個數組中添加就可以。
這些準備工作做完之後,還需要明白一點就是,在java層中System.loadLibrary這個方法加載本地庫之後,會調用JNI_OnLoad這個方法,這就是動態註冊的一個入口函數。我們可以模仿系統的JNI_OnLoad的方法進行對應的處理。
extern "C"
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved){
LOGD("JNI_OnLoad");
JNIEnv* env=NULL;
jint result=-1;
if ((vm)->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGI("ERROR: GetEnv failed\n");
return -1;
}
assert(env != NULL);
registerNatives(env); //前面都是一些檢查工作,這一步是進行調用註冊
return JNI_VERSION_1_4;
}
registerNatives這個方法是關鍵,也需要本地自己實現,這個方法接受一個參數JNIEnv*
static int registerNatives(JNIEnv* env){
LOGD("registerNatives Begin !");
jclass jclz=env->FindClass("com/soft/lpf/LiveUtils"); //需要註冊的java文件路徑,動態註冊的方法需要在這個文件中
if (jclz==NULL){
LOGD("jclass is NULL");
return JNI_FALSE;
}
if (env->RegisterNatives(jclz,gMethods,NELEM(gMethods))<0){ //這一步是進行動態註冊
LOGD("RegistterNatives error");
return JNI_FALSE;
}
return JNI_TRUE;
};
經過以上幾步便完成了,動態註冊了,在java層邊可以正常調用live方法了。這樣便於移植,而且效率也比較高,如果需要註冊其他的方法,只需要在方法數組中添加即可,非常方便。鑑於本作者水平有限,如有不足,請多多指正。