2012-09-14 8 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; 
} 

編集

私は私のinitが実際に「勝った私のcプログラムのmain方法であるためglobalEnvPointerを使用するすべてのメソッドは、私のinit内で呼び出され、ここではビットダムビングよプログラムが終了するまで戻りません。私はまた、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スレッドと同じように機能します。ネイティブスレッドは、DetachCurrentThread()を呼び出して自身をデタッチするまで、VMに接続されたままです。

代わりに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

関連する問題