2012-09-14 9 views
27

Ich speichere von JNIEnv in einem globalen, damit ich statische Methoden später aufrufen kann. Aber ist es notwendig, einen globalen Zeiger auf die JNIEnv zu speichern, so wie man es mit jedem anderen Java-Objekt machen würde, oder ist es ein Spezialfall, der dies nicht erfordert.Behalten Sie einen globalen Verweis auf die JNIEnv-Umgebung

JNIEnv* globalEnvPointer; 

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

bearbeiten

ich hier ein bisschen dumm bin bing, alle Methoden, die globalEnvPointer, sind in meinem init aufgerufen, weil mein init ist eigentlich mein c Programm main Methode, die ‚gewonnen verwenden t Rückkehr bis zum Ende des Programms. Ich verwende auch keine anderen Threads im c-Programm. Ich denke, das vereinfacht die Antwort.

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 
} 

Antwort

41

Sie können den Zeiger JNIEnv nicht zwischenspeichern. Lesen Sie darüber here:

Der JNI-Schnittstellenzeiger (JNIEnv) ist nur im aktuellen Thread gültig. Wenn ein anderer Thread auf die Java-VM zugreifen muss, muss er zuerst AttachCurrentThread() aufrufen, um sich an die VM anzuhängen und einen JNI-Schnittstellenzeiger zu erhalten. Sobald ein nativer Thread an die VM angehängt ist, funktioniert er wie ein normaler Java-Thread, der in einer nativen Methode ausgeführt wird. Der native Thread bleibt mit der VM verbunden, bis er DetachCurrentThread() aufruft, um sich selbst zu lösen.

Sie können stattdessen den Zeiger JavaVM zwischenspeichern.

static JavaVM *jvm; 

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

Und dann, wann immer Sie brauchen dann JNIEnv Zeiger von einem Kontext, in dem es nicht gegeben Sie dies tun:

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

Aber wenn Sie eine native Methode von Java das env-Zeiger aufrufen wird die Verwendung gegeben :

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

Es ist alles ein Thread, macht das einen Unterschied? d. h. mein 'init' wird im selben Thread aufgerufen wie später die statischen Java-Methoden. – weston

+0

Verwenden Sie immer den 'JNIEnv'-Zeiger, der in der C-Funktion eingeht. Wie in meinem letzten Beispiel. – maba

+0

Bitte sehen Sie meine Bearbeitung, in Ihrem Beispiel, wenn 'Java_package_Class_method'' someCallback' genannt wird, müssten Sie nicht über 'JavaVM' gehen, oder? In der Tat ist das, was ich tue, nur mit einem globalen, anstatt es an "someCallback" zu übergeben. – weston

Verwandte Themen