静态注册
根据函数名来建立java方法和JNI函数间的一一对应关系。
JNI调用函数名称是按照一定的规则去生成的,规则如下:
1.后期类名、文件名改动,头文件所有函数将失效,需要手动改,特别容易出错
2.代码编写不方便,由于JNI层函数的名字必须遵循特定的格式,且名字特别长;
3.程序运行效率低,因为初次调用native函数时需要根据根据函数名在JNI层中搜索对应的本地函数,然后建立对应关系,这个过程比较耗时。
动态注册
直接告诉native函数其在JNI中对应函数的指针
使用一种数据结构JNINativeMethod来记录java native函数和JNI函数的对应关系,移植方便
动态注册demo:
private native String dynamicRegisterJNI();
TextView textView= (TextView) findViewById(R.id.sample_text);
textView.setText(dynamicRegisterJNI());
#include <jni.h>
#include <string>
#include<stdlib.h>
#include <android/log.h>
#include <assert.h>
#define TAG "HZP_JNI"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
// 获取数组的大小
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
JNIEXPORT jstring JNICALL native_dynamicRegisterJNI
(JNIEnv *env, jclass clazz)
{
LOGI("JNI begin 动态注册的方法 ");
const char *p="我是动态注册返回的值";
return env->NewStringUTF(p);
}
const JNINativeMethod gMethods[] = {
{
"dynamicRegisterJNI","()Ljava/lang/String;",(void*)native_dynamicRegisterJNI
}
};
int registerNatives(JNIEnv* engv)
{
LOGI("registerNatives begin");
jclass clazz;
clazz = engv -> FindClass("com/example/huozhenpeng/myapplication/MainActivity");
if (clazz == NULL) {
LOGI("clazz is null");
return JNI_FALSE;
}
if (engv ->RegisterNatives( clazz, gMethods, NELEM(gMethods)) < 0) {
LOGI("RegisterNatives error");
return JNI_FALSE;
}
return JNI_TRUE;
}
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
LOGI("jni_OnLoad begin");
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;
}
测试结果:

image.png
JNINativeMethod是一个结构体,看下定义
typedef struct {
const char* name; /*Java 中函数的名字*/
const char* signature; /*描述了函数的参数和返回值*/
void* fnPtr; /*函数指针,指向 C 函数*/
} JNINativeMethod;