我了解到JNI接口指针(JNIEnv *)仅在当前线程中有效。假设我在本机方法中启动了一个新线程;如何将事件异步发送到Java方法?由于此新线程不能具有(JNIEnv *)的引用。为(JNIEnv *)存储全局变量显然无法正常工作吗?
Answers:
在使用从Java到C ++的JNI进行的同步调用中,JVM已设置了“环境”,但是从任意C ++线程的另一个方向来看,可能没有
因此,您需要按照以下步骤
GetEnv
AttachCurrentThread
CallVoidMethod
DetachCurrentThread
完整的例子。请注意,我过去在博客中详细介绍了此内容
JavaVM* g_vm;
env->GetJavaVM(&g_vm);
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();
}
您可以使用来获得指向JVM(JavaVM*
)的指针JNIEnv->GetJavaVM
。您可以安全地将该指针存储为全局变量。以后,在新线程中,AttachCurrentThread
如果您是用C / C ++创建的,则可以用来将新线程附加到JVM,或者只是GetEnv
用Java代码创建的线程(我不认为这是因为JNI会给您传递JNIEnv*
then和你不会有这个问题。
// 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
AttachCurrentThread
如果您不需要任何特殊设置,则to的第二个参数可以为NULL,并且DetachCurrentThread
如果不附加开头,则应确保在完成时调用(否则,您将积累无用的Thread
对象,这些对象可以(永远不会被GC))。
JNIEnv->GetJavaVM
接受env
作为第一个参数吗?
env
基本上是第一个参数,因为它GetJavaVM
是在env
指针上调用的。
GetEnv
,AttachCurrentThread
并且DetachCurrentThread
甚至没有解释。