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方法了。这样便于移植,而且效率也比较高,如果需要注册其他的方法,只需要在方法数组中添加即可,非常方便。鉴于本作者水平有限,如有不足,请多多指正。

 

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