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++ 共有オブジェクトを呼び出します。次に、最初に保存したジョブジェクトを使用して元の 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 に答える