如何获取asynchronous调用的JNI接口指针(JNIEnv *)
我已经了解到,JNI接口指针(JNIEnv *)只在当前线程中有效。 假设我在本地方法中启动了一个新线程; 如何将事件asynchronous发送到Java方法? 由于这个新线程不能有(JNIEnv *)的引用。 (JNIEnv *)的全局variables显然不起作用?
在使用从Java到C ++的JNI的同步调用中,“环境”已经由JVM设置,但是从任意C ++线程走向另一个方向可能不是
所以你需要按照这些步骤
- 使用
GetEnv
获取JVM环境上下文 - 根据需要使用
AttachCurrentThread
附加上下文 - 使用
CallVoidMethod
正常调用方法 - 使用
DetachCurrentThread
分离
完整的例子。 注意我在我的博客上更详细地写过这个
void callback(int val) { JNIEnv * g_env; // double check it's all ok int getEnvStat = g_vm->GetEnv((void **)&g_env, JNI_VERSION_1_6); if (getEnvStat == JNI_EDETACHED) { std::cout << "GetEnv: not attached" << std::endl; if (g_vm->AttachCurrentThread((void **) &g_env, NULL) != 0) { std::cout << "Failed to attach" << std::endl; } } else if (getEnvStat == JNI_OK) { // } else if (getEnvStat == JNI_EVERSION) { std::cout << "GetEnv: version not supported" << std::endl; } g_env->CallVoidMethod(g_obj, g_mid, val); if (g_env->ExceptionCheck()) { g_env->ExceptionDescribe(); } g_vm->DetachCurrentThread(); }
您可以使用JNIEnv->GetJavaVM
获取指向JVM( JavaVM*
)的指针。 您可以安全地将该指针存储为全局variables。 后来,在新的线程中,如果你在C / C ++中创build它,你可以使用AttachCurrentThread
来附加新线程到JVM,或者如果你在java代码中创build了线程,那么我们不会假设,因为JNI会通过你JNIEnv*
然后你就不会有这个问题。
// JNIEnv* env; (initialized somewhere else) JavaVM* jvm; env->GetJavaVM(&jvm); // now you can store jvm somewhere // in the new thread: JNIEnv* myNewEnv; JavaVMAttachArgs args; args.version = JNI_VERSION_1_6; // choose your JNI version args.name = NULL; // you might want to give the java thread a name args.group = NULL; // you might want to assign the java thread to a ThreadGroup jvm->AttachCurrentThread((void**)&myNewEnv, &args); // And now you can use myNewEnv