24

我有一个通过 JNI 调用 C++ 共享对象的 java 对象。在 C++ 中,我保存了对 JNIEnv 和 jObject 的引用。

JavaVM * jvm;
JNIEnv * myEnv;
jobject myobj;

JNIEXPORT void JNICALL Java_org_api_init
   (JNIEnv *env, jobject jObj) {
    myEnv = env;
    myobj = jObj;
}

我还有一个 GLSurface 渲染器,它最终在另一个线程 GLThread 上调用上面提到的 C++ 共享对象。然后我尝试使用我最初保存的 jobject 回调我的原始 Java 对象,但我认为因为我在 GLThread 上,所以我收到以下错误。

W/dalvikvm(16101): JNI WARNING: 0x41ded218 is not a valid JNI reference
I/dalvikvm(16101): "GLThread 981" prio=5 tid=15 RUNNABLE
I/dalvikvm(16101):   | group="main" sCount=0 dsCount=0 obj=0x41d6e220 self=0x5cb11078
I/dalvikvm(16101):   | sysTid=16133 nice=0 sched=0/0 cgrp=apps handle=1555429136
I/dalvikvm(16101):   | schedstat=( 0 0 0 ) utm=42 stm=32 core=1

回调到 Java 的代码:

void setData()
    {
        jvm->AttachCurrentThread(&myEnv, 0);

        jclass javaClass = myEnv->FindClass("com/myapp/myClass");
        if(javaClass == NULL){
            LOGD("ERROR - cant find class");
        }

        jmethodID method = myEnv->GetMethodID(javaClass, "updateDataModel", "()V");
        if(method == NULL){
            LOGD("ERROR - cant access method");
        }

        // this works, but its a new java object
        //jobject myobj2 = myEnv->NewObject(javaClass, method);

        //this is where the crash occurs
        myEnv->CallVoidMethod(myobj, method, NULL); 

}

相反,如果我使用 env->NewObject 创建一个新的 jObject,我可以成功回调到 Java,但它是一个新对象,我不想要那个。我需要回到我原来的 Java 对象。

在我回调Java之前切换线程是否有问题?如果是这样,我该怎么做?

4

1 回答 1

39

从不同的线程访问对象很好。问题是 JNI 调用获取对象作为本地引用。如果要在 JNI 调用之间保留对 jobject 的引用,则需要将其设为全局引用:

myobj = env->NewGlobalRef(jObj);

记得在你用完之后释放它,否则垃圾收集器不会收集它,你会得到内存泄漏:

myEnv->DeleteGlobalRef(myobj);

在此处阅读有关全局与本地参考的信息。

于 2012-12-20T05:02:28.200 回答