2012-11-14 49 views
1

我有一個Android應用程序,它由一些本地線程(不附加到JVM)組成,它需要能夠調用Java對象的方法。本地多線程和JNI

我打算這樣做的方式是創建一個JNI函數,我從相關的Java對象中調用它,它允許我獲取並緩存所需的java對象方法ID,JNIEnv和對象引用的靜態本機數據結構,以便我的本地線程可以(線程安全地)訪問所需的方法(例如使用(* env) - > CallVoidMethod(env,this,JavaMethodID,...)等;

我不相信方法是行得通的,因爲我讀過JNIEnv指針不能在線程之間共享,只有連接到JVM的線程才能做這種事情......

這是一種可行的方法嗎?

+0

'JNIEnv'只適用於當前線程,但'JavaVM'是全球性的。所以,保存一個指向它的指針,以及對你的類,對象,方法ID的全局引用,這將起作用。 –

+0

http://developer.android.com/training/articles/perf-jni.html – fadden

回答

2
  1. in JNI_OnLoad,cache JavaVM*。這是跨線程唯一持久和有效的事情。
  2. 只要您設置了一些本地線程,請致電AttachCurrentThread並獲得JNIEnv*,它僅對該單線程有效。
  3. JavaVM*JNIEnv*,查找您的jclass es,jobject s和jmethodID s。 這些僅對您附加的單線程有效。
  4. jclass es和jobject s轉換爲全局引用,以便它在整個線程中保持不變。 jmethodID不需要全球化,他們不是工作對象。
  5. 在任何進一步的本地線程上,您需要再次調用AttachCurrentThread以獲取該線程的有效JNIEnv*
  6. 不要忘記刪除已創建的全局引用,當你不(在最新的JNI_OnUnload)需要它們了
+0

謝謝帕維爾,這正是我一直在尋找的東西。爲了澄清一下,一旦我緩存了方法ID並將我的類和對象引用全局化後,所有後續線程都可以使用相同的方法ID(例如,在CallVoidMethod()中),只要它們通過它們自己的JNIEnv *進行操作即可,如5中所述。我不必爲每個線程獲取一組新的方法ID,對嗎? –

+0

是的,方法ID在任何地方都有效。只有參考類型需要「全球化」,這是來自jobject的任何事情。 jmethodID不是jobject,它是「[不透明結構](http://docs.oracle.com/javase/1.3/docs/guide/jni/spec/types.doc.html#1064)」。我的理論是,它只是類的函數表中的某種順序索引(如C++的vtable),因此對於該類的所有實例都是相同的。 –

+0

這很好,再次感謝。我會投你的答案爲'有用',但還沒有足夠的聲譽。 –