2012-09-14 11 views
27

Sto memorizzando JNIEnv in modo globale, quindi è possibile chiamare i metodi java statici in un secondo momento. Ma è necessario memorizzare un puntatore globale sullo JNIEnv, come se fosse un qualsiasi altro oggetto java, oppure è un caso speciale che non richiede questo.Mantenere un riferimento globale all'ambiente JNIEnv

JNIEnv* globalEnvPointer; 

[JNICALL etc] void init(JNIENv* env, [etc]) 
{ 
    //required? 
    globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env); 
    //or is this OK? 
    globalEnvPointer = env; 
} 

Modifica

sto bing un po 'stupido qui, tutti i metodi che utilizzeranno globalEnvPointer, vengono richiamati nel mio init perché il mio init è in realtà il metodo mio programma di cmain, che ha vinto' t ritorno fino alla fine del programma. Sto anche usando nessun altro thread nel programma c. Penso che questo semplifica la risposta.

JNIEnv* globalEnvPointer; 

[JNICALL etc] void main(JNIENv* env, [etc]) 
{ 
    //required? 
    globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env); 
    //or is this OK? 
    globalEnvPointer = env; 
    someMethod(); 
} 

void someMethod() 
{ 
    //use globalEnvPointer here 
} 

risposta

41

Non è possibile memorizzare nella cache il puntatore JNIEnv. Informazioni a riguardo here:

Il puntatore all'interfaccia JNI (JNIEnv) è valido solo nel thread corrente. Se un altro thread deve accedere alla Java VM, è prima necessario chiamare AttachCurrentThread() per collegarsi alla VM e ottenere un puntatore all'interfaccia JNI. Una volta collegato alla VM, un thread nativo funziona come un normale thread Java eseguito all'interno di un metodo nativo. Il thread nativo rimane collegato al VM fino a quando non chiama DetachCurrentThread() per staccarsi.

È possibile memorizzare nella cache il puntatore JavaVM.

static JavaVM *jvm; 

[JNICALL etc] void init(JNIENv* env, [etc]) 
{ 
    jint rs = (*env)->GetJavaVM(env, &jvm); 
    assert (rs == JNI_OK); 
} 

E poi ogni volta che è necessario quindi JNIEnv puntatore da un contesto in cui non è dato si esegue questa operazione:

void someCallback() { 
    JNIEnv *env; 
    jint rs = (*jvm)->AttachCurrentThread(jvm, &env, NULL); 
    assert (rs == JNI_OK); 
    // Use the env pointer... 
} 

Ma ogni volta che si chiama un metodo nativo da Java il puntatore env per utilizzare è dato :

JNIEXPORT jint JNICALL Java_package_Class_method(JNIEnv *env, jobject obj) { 
    // just use the env pointer as is. 
} 
+0

È tutto un thread, fa la differenza? Ad esempio, il mio 'init' viene chiamato nello stesso thread che chiamerà in seguito i metodi java statici. – weston

+0

Usa sempre il puntatore 'JNIEnv' che sta entrando nella funzione C. Come nel mio ultimo esempio. – maba

+0

Per favore vedi la mia modifica, nel tuo esempio, se 'Java_package_Class_method' ha chiamato' someCallback', non avresti bisogno di passare tramite 'JavaVM', vero? In effetti questo è quello che sto facendo, semplicemente usando un global piuttosto che passarlo a 'someCallback'. – weston

Problemi correlati