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