在此之前我们一直在jni中使用Java_PACKAGENAME_CLASSNAME_METHODNAME 来进行与java方法的匹配,这种方式我们称之为静态注册。
而动态注册则意味着方法名可以不用这么长了,在android aosp源码中就大量的使用了动态注册的形式。
MainActivity.java
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dynamicJavaTest();
dynamicJavaTest2(5);
}
native void dynamicJavaTest();
native int dynamicJavaTest2(int i);
}
static {
System.loadLibrary("native-lib");
}
这句执行,会立刻调用native-lib.cpp中的JNI_OnLoad这个方法
native-lib.cpp
#include <jni.h>
#include <string>
#include <android/log.h>
#define LOG_TAG "atguigu"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGE(...) __android_log_print(ERROR,LOG_TAG ,__VA_ARGS__) // 定义LOGD类型
JavaVM *_vm;
void dynamicTest(){
LOGI("JNI dynamicTest");
}
jint dynamicTest2(JNIEnv *env, jobject instance,jint i){
LOGI("JNI dynamicTest2:%d",i);
return 100;
}
static const JNINativeMethod method[] = {
{"dynamicJavaTest","()V",(void*)dynamicTest},
{"dynamicJavaTest2","(I)I",(int*)dynamicTest2}
};
static const char *mClassName = "com/example/myapplication/MainActivity";
int JNI_OnLoad(JavaVM *vm,void *re){
LOGI("JNI_Onload方法初始化");
_vm = vm;
//获得JNIEnv
JNIEnv *env = 0;
int r = vm->GetEnv((void**)&env,JNI_VERSION_1_6);
//小于0失败,等于0成功
if(r != JNI_OK){
return -1;
}
//获得class对象
jclass jcls = env->FindClass(mClassName);
//动态注册
env->RegisterNatives(jcls,method, sizeof(method)/ sizeof(JNINativeMethod));
return JNI_VERSION_1_6;
}
代码详解:
我们使用RegisterNatives这个方法来进行动态注册,RegisterNatives的原型为:
jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,
jint nMethods)
第二个参数为JNINativeMethod,它是一个结构体:
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
然后我们来使用一个数组来构造这个结构体:
static const JNINativeMethod method[] = {
{"dynamicJavaTest","()V",(void*)dynamicTest},
{"dynamicJavaTest2","(I)I",(int*)dynamicTest2}
};
dynamicJavaTest和dynamicJavaTest2为Java中的native方法。
()V 和 (I)I分别为两个方法的签名
(void)dynamicTest和(int)dynamicTest2为JNI中对应的两个方法,这两个方法都是Java调用C的方法。
要注意的是JNI中的这两个方法的参数JNIEnv *env在什么时候传递:
void dynamicTest(){//无参数时不用加JNIEnv *env, jobject instance
LOGI("JNI dynamicTest");
}
//有参数时如jint i时需要加上JNIEnv *env, jobject instance,否则会把参数当作JNIEnv
jint dynamicTest2(JNIEnv *env, jobject instance,jint i){
LOGI("JNI dynamicTest2:%d",i);
return 100;
}
网友评论