2012-12-20 11 views
13

Ho un oggetto java che chiama in un oggetto condiviso C++ tramite JNI. In C++, sto salvando un riferimento a JNIEnv e jObject.Chiamare in un oggetto java salvato tramite JNI da una filettatura diversa

JavaVM * jvm; 
JNIEnv * myEnv; 
jobject myobj; 

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

Ho anche un renderer GLSurface e alla fine chiama il C++ oggetto condiviso di cui sopra in un thread diverso, il GLTHREAD. Sto quindi cercando di richiamare il mio oggetto Java originale usando il jobject che ho salvato inizialmente, ma penso che sia perché sono sul GLThread, ottengo il seguente errore.

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 

Il codice di richiamare in 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); 

}

Se invece creo un nuovo jobject usando env> NewObject, posso succuessfully richiamato in Java, ma è un nuovo oggetto e non lo voglio Devo tornare al mio oggetto Java originale.

Si tratta di passare i thread prima di richiamare in Java? Se sì, come faccio?

risposta

24

L'accesso all'oggetto da thread diversi va bene. Il problema è che le chiamate JNI ottengono oggetti come riferimenti locali. Se si desidera mantenere riferimento alla jobject tra JNI chiamate è necessario renderlo riferimento globale:

myobj = env->NewGlobalRef(jObj); 

Ricordatevi di liberarla dopo aver finito di usarlo altrimenti garbage collector non raccoglie e si otterrà perdite di memoria:

myEnv->DeleteGlobalRef(myobj); 

Leggi su globale vs riferimenti locali here.

+1

ha funzionato perfettamente! –

+0

Vedere anche http://developer.android.com/training/articles/perf-jni.html per questo e altri suggerimenti. – fadden

+0

Grazie ... Semplice e funziona perfettamente –

Problemi correlati