2012-09-14 53 views
27

我在全局中存儲JNIEnv以便稍後可以調用靜態java方法。但是,將一個指向JNIEnv的全局指針存儲起來非常麻煩,它們可以與任何其他java對象一起使用,或者是不需要這種特殊情況的特殊情況。保持對JNIEnv環境的全局引用

JNIEnv* globalEnvPointer; 

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

編輯

我兵在這裏有點啞,都將使用globalEnvPointer的方法,是我的init中調用,因爲我init實際上是我c程序main方法,從而贏得了」直到程序結束。我也沒有在c程序中使用其他線程。我認爲這簡化了答案。

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 
} 

回答

41

無法緩存JNIEnv指針。閱讀關於它here

JNI接口指針(JNIEnv)僅在當前線程中有效。如果另一個線程需要訪問Java VM,它必須首先調用AttachCurrentThread()將其自身附加到VM並獲得一個JNI接口指針。一旦連接到VM,本地線程就像在本地方法內運行的普通Java線程一樣工作。本地線程保持連接到VM,直到它調用DetachCurrentThread()來分離它自己。

您可以做的是高速緩存JavaVM指針。

static JavaVM *jvm; 

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

然後每當你從那裏不給你做這方面需要再JNIEnv指針:

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

但每當你從Java調用本地方法的ENV指針使用給出:

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

這都是一個線程,這是否有所作爲?即我的'init'被調用與之後調用靜態java方法的線程相同。 – weston

+0

始終使用C函數中的'JNIEnv'指針。就像我最後一個例子。 – maba

+0

請看我的編輯,在你的例子中,如果'Java_package_Class_method'調用'someCallback',你不需要通過'JavaVM'去嗎?實際上,這就是我正在做的,只是使用全局而不是傳遞給'someCallback'。 – weston