保持对JNIEnv环境的全局引用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了保持对JNIEnv环境的全局引用相关的知识,希望对你有一定的参考价值。

我将JNIEnv存储在全局中,所以我稍后可以调用静态java方法。但是存储一个指向JNIEnv的全局指针是不是必要的,它们可以与任何其他java对象一起存储,或者它是一个不需要它的特殊情况。

JNIEnv* globalEnvPointer;

[JNICALL etc] void init(JNIENv* env, [etc])
{
   //required?
   globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env);
   //or is this OK?
   globalEnvPointer = env;
}

编辑

我在这里有点愚蠢,所有使用globalEnvPointer的方法都在我的init中调用,因为我的init实际上是我的c程序的main方法,直到程序结束才会返回。我也在c程序中没有使用其他线程。我认为这简化了答案。

JNIEnv* globalEnvPointer;

[JNICALL etc] void main(JNIENv* env, [etc])
{
   //required?
   globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env);
   //or is this OK?
   globalEnvPointer = env;
   someMethod();
}

void someMethod()
{
   //use globalEnvPointer here
}
答案

你无法缓存JNIEnv指针。了解它here

JNI接口指针(JNIEnv)仅在当前线程中有效。如果另一个线程需要访问Java VM,它必须首先调用AttachCurrentThread()以将自身附加到VM并获取JNI接口指针。一旦连接到VM,本机线程就像在本机方法中运行的普通Java线程一样工作。本机线程保持连接到VM,直到它调用DetachCurrentThread()来分离自身。

你可以做的是缓存JavaVM指针。

static JavaVM *jvm;

[JNICALL etc] void init(JNIENv* env, [etc])
{
   jint rs = (*env)->GetJavaVM(env, &jvm);
   assert (rs == JNI_OK);
}

然后,只要你需要那么JNIEnv指针从没有给出的上下文你这样做:

void someCallback() {
    JNIEnv *env;
    jint rs = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
    assert (rs == JNI_OK);
    // Use the env pointer...
}

但是无论何时从Java调用本机方法,都会给出使用的env指针:

JNIEXPORT jint JNICALL Java_package_Class_method(JNIEnv *env, jobject obj) {
    // just use the env pointer as is.
}

以上是关于保持对JNIEnv环境的全局引用的主要内容,如果未能解决你的问题,请参考以下文章

Android JNI 学习:JNI 接口整理 — References Api

浅谈如何用JNI的代码调用java接口

[转]JNIEnv解析

片段对话框对活动的松散引用

对“xxx”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。 错误解决一例。(代码片段

php中的全局变量引用