本篇主要讲解JNI的一些高级写法和线程,文章内容都非常简单。
JNI_OnLoad
上一章讲的JNI 编程详解
Java 要调用C++的方法,都要写一大长串比如:
extern "C"
JNIEXPORT void JNICALL
Java_com_jnimode1_MainActivity_updateGolbal(JNIEnv *env, jobject instance, jclass jclass1)
上述相当于静态注册,而JNI_OnLoad是动态注册,两者其实没什么区别,简化了方法名让人更容易理解。
简化后
void updateGolbal(jclass cls)
下面我们看一个例子就理解了,都有注释,so easy
JavaVM *_vm;
void dynamicTest() {
LOGE("我是被动态注册的方法dynamicTest");
}
//JNIEnv *env, jobject instance 如果传参数这两个参数必须存在
jint dynamicTest2(JNIEnv *env, jobject instance, jint i) {
LOGE("我是被动态注册的方法dynamicTest2");
return i;
}
//静态的Jni native 方法数组
static const JNINativeMethod method[] = {
//方法名 签名 本地方法
{"dynamicJavaTest", "()V", (void *) dynamicTest},
{"dynamicJavaTest2", "(I)I", (int *) dynamicTest2}
};
//类名
static const char *mClassName = "com/jnimode1/MainActivity";
//返回Jni 版本
int JNI_OnLoad(JavaVM *vm, void *r) {
LOGE("JNI_OnLoad");
_vm = vm;
JNIEnv *env = 0;
//获得JNIEnv 这里会返回一个值 小于0 代表失败
jint res = vm->GetEnv((void **) (&env), JNI_VERSION_1_6);
//判断返回结果
if (res != JNI_OK) {
return -1;
}
//根据类名找到类,注意有native的类不能被混淆
jclass jcls = env->FindClass(mClassName);
//动态注册 第一个参数 类 第二个参数 方法数组 第三个参数 注册多少个方法
env->RegisterNatives(jcls, method, sizeof(method) / sizeof(JNINativeMethod));
return JNI_VERSION_1_6;
}
Activity 中调用
public native void dynamicJavaTest();
public native int dynamicJavaTest2(int i);
native线程调用Java
native调用java需要使用JNIEnv这个结构体,而JNIEnv是由Jvm传入与线程相关的变量。
但是可以通过JavaVM的AttachCurrentThread方法来获取到当前线程中的JNIEnv指针。
jobject _instance;
void *task(void *args){
JNIEnv *env;
//将本地当前线程附加到 jvm 并获得jnienv
//成功则返回0
jint res = _vm->AttachCurrentThread(&env,0);
if (res != JNI_OK){
return 0;
}
jclass jclass1 = env->GetObjectClass(_instance);
jmethodID staticMethod = env->GetStaticMethodID(jclass1,"staticMothed","(I)V");
env->CallStaticVoidMethod(jclass1,staticMethod,100);
jmethodID jmethodID1 = env->GetMethodID(jclass1,"instanceMothed","(Ljava/lang/String;)V");
jstring jstring1 = env->NewStringUTF("我是C++");
env->CallVoidMethod(_instance,jmethodID1,jstring1);
env->DeleteLocalRef(jclass1);
env->DeleteLocalRef(jstring1);
env->DeleteGlobalRef(_instance);
//分离
_vm->DetachCurrentThread();
return 0;
}
void nativeThread2(JNIEnv *env,jobject instace){
_instance = env->NewGlobalRef(instace);//_instacne 设置为全局引用
pthread_t pthread;
pthread_create(&pthread,0,task,0);
}