jni 新手笔记五:JNIEnv & JavaVM
2019-03-23 本文已影响0人
DON_1007
c
与c++
的JNIEnv
不同
c
,指针变量
typedef const struct JNINativeInterface* JNIEnv;
使用的时候 (*pEnv)->GetObjectClass(pEnv,obj);
c++
,直接指向结构体
struct _JNIEnv;
struct _JavaVM;
typedef const struct JNINativeInterface* C_JNIEnv;
#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
使用的时候pEnv->GetObjectClass(obj);
不同线程间的JNIEnv
不同,换句话说,就是在线程A
中的JNIEnv
,在线程B
中不能使用。
JavaVM
一个进程只有一个,java
代码调用c++
代码的时候jni
给了一个JNIEnv
变量,但是如果在c++
中新创建了一个子线程C
用于处理任务,那么在子线程C
中不能使用前面的那个JNIEnv
。如果子线程
中想要使用JNIEnv
,只能通过JavaVM
得到一个新的JNIEnv
,在子线程
中使用。
一、获取JavaVM
1、通过JNIEnv
获取JavaVM
JNIEXPORT jstring JNICALL Java_com_don_ndk_NDKTest_getHello
(JNIEnv *pEnv, jobject obj, jint param) {
pEnv->GetJavaVM(&javaVM);
jstring result = pEnv->NewStringUTF(getHello());
return result;
}
2、实现JNI_OnLoad
方法,获取JavaVM
在加载动态链接库的时候,JVM
会调用JNI_OnLoad(JavaVM* jvm, void* reserved)
(如果定义了该函数),第一个参数会传入JavaVM
指针。
JavaVM *javaVM = NULL;
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
javaVM = vm;
LOGI("JNI_OnLoad ndk test");
return JNI_VERSION_1_4;
}
二、通过JavaVM
获取JNIEnv
创建子线程执行方法doThreadThing
,通过calljstringMethod
调用java
代码
void threadTest() {
pthread_create(&pthread, NULL, doThreadThing, NULL);
}
void *doThreadThing(void *data) {
LOGI("doThreadThing ****************");
if (javaVM == NULL) {
LOGW("doThreadThing invalid javaVM");
return NULL;
}
JNIEnv *jniEnv = NULL;
jint ret = javaVM->GetEnv((void **) &jniEnv, JNI_VERSION_1_4);
LOGI("doThreadThing ret: %d", ret);
if (ret == JNI_EDETACHED) {
if (javaVM->AttachCurrentThread(&jniEnv, NULL) != JNI_OK) {
LOGW("doThreadThing AttachCurrentThread failed");
return NULL;
} else {
LOGI("doThreadThing AttachCurrentThread success");
}
}
if (jniEnv == NULL) {
LOGW("doThreadThing invalid jniEnv");
return NULL;
} else {
LOGI("doThreadThing get JNIEnv success");
}
calljstringMethod(jniEnv, jniObj);
javaVM->DetachCurrentThread();
pthread_exit(&pthread);
}
jniObj
是在 Java_com_don_ndk_NDKTest_getHello
方法中保存的jobject
变量
pthread_t pthread;
JavaVM *javaVM = NULL;
jobject jniObj = NULL;
JNIEXPORT jstring JNICALL Java_com_don_ndk_NDKTest_getHello
(JNIEnv *pEnv, jobject obj, jint param) {
jstring result = pEnv->NewStringUTF(getHello());
pEnv->GetJavaVM(&javaVM);
jniObj = pEnv->NewGlobalRef(obj);
threadTest();
return result;