NDK基礎二 JNI 動態註冊

靜態註冊:

在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方法了。這樣便於移植,而且效率也比較高,如果需要註冊其他的方法,只需要在方法數組中添加即可,非常方便。鑑於本作者水平有限,如有不足,請多多指正。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章