2012-12-20 6 views
13

Mam obiekt java, który wywołuje obiekt współdzielony w C++ przez JNI. W C++ zapisuję odniesienie do JNIEnv i jObject.Wywołanie zapisanego obiektu Javy przez JNI z innego wątku

JavaVM * jvm; 
JNIEnv * myEnv; 
jobject myobj; 

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

Mam również rendererz GLSurface i ostatecznie wywołuje współużytkowany obiekt C++ wspomniany powyżej w innym wątku, GLThread. Próbuję następnie wywołać z powrotem do mojego pierwotnego obiektu Java przy użyciu jobject I zapisane początkowo, ale Myślę, że ponieważ jestem na GLThread, otrzymuję następujący błąd.

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 

Kod oddzwanianie w Javie:

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

}

Jeśli zamiast tworzyć nowy jObject korzystając env-> NewObject mogę succuessfully oddzwonić do Javy, ale jest nowy obiekt i nie chcę tego. Muszę wrócić do mojego oryginalnego obiektu Java.

Czy to kwestia zmiany wątków przed ponownym wywołaniem w Javie? Jeśli tak, jak mam to zrobić?

Odpowiedz

24

Uzyskiwanie dostępu do obiektu z różnych wątków jest w porządku. Problem polega na tym, że wywołania JNI otrzymują obiekty jako lokalne odwołania. Jeśli chcesz zachować odniesienie do jobject między JNI wzywa trzeba zrobić to globalny odniesienie:

myobj = env->NewGlobalRef(jObj); 

Pamiętaj, aby uwolnić go po skończysz korzystali inaczej śmieciarza nie zbierze go i dostaniesz wycieki pamięci:

myEnv->DeleteGlobalRef(myobj); 

Przeczytaj o referencjach global vs local here.

+1

działa idealnie! –

+0

Zobacz także http://developer.android.com/training/articles/perf-jni.html dla tego i innych wskazówek. – fadden

+0

Dziękuję ... Proste i działa doskonale –