2012-12-20 5 views
13

Ich habe ein Java-Objekt, das über JNI in ein freigegebenes C++ - Objekt aufruft. In C++ speichere ich einen Verweis auf JNIEnv und jObject.Aufruf in ein gespeichertes Java-Objekt über JNI aus einem anderen Thread

JavaVM * jvm; 
JNIEnv * myEnv; 
jobject myobj; 

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

Ich habe auch einen GLSurface Renderer und ruft schließlich die C++ Shared Object oben erwähnt auf einem anderen Thread, die GLTHREAD. Ich versuche dann, in mein ursprüngliches Java-Objekt zurückzurufen, das das jobject verwendet, das ich zuerst speicherte, aber ich denke weil ich auf dem GLThread bin, erhalte ich den folgenden Fehler.

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 

Der Code zurück in Java Aufruf:

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); 

}

Wenn ich stattdessen einen neuen jObject mit env> NewObject schaffen, ich succuessfully zurück in Java nennen kann, aber es ist ein neues Objekt und das will ich nicht. Ich muss zu meinem ursprünglichen Java-Objekt zurückkehren.

Geht es darum, Threads zu wechseln, bevor ich in Java zurückrufe? Wenn ja, wie mache ich das?

Antwort

24

Zugriff auf Objekt von verschiedenen Threads ist in Ordnung. Problem ist, dass JNI ruft Objekte als lokale Referenzen. Wenn Sie Referenz behalten möchten jobject zwischen JNI nennt man es globale Referenz zu machen brauchen:

myobj = env->NewGlobalRef(jObj); 

Denken Sie daran, es zu befreien, nachdem Sie fertig sind mit es sonst Garbage Collector nicht sammeln und Sie erhalten Speicherlecks:

myEnv->DeleteGlobalRef(myobj); 

Lesen Sie über globale vs lokale Referenzen here.

+1

hat perfekt funktioniert! –

+0

Siehe auch http://developer.android.com/training/articles/perf-jni.html für diese und andere Tipps. – fadden

+0

Danke ... Einfach und es funktioniert perfekt –

Verwandte Themen