Android Studio NDK開發:JNI呼叫Java函式

姜家志發表於2016-06-21

相對於NDK來說SDK裡面有更多API可以呼叫,有的時候我們在做NDK開發的時候,需要在JNI直接呼叫Java中的函式,比如callback,系統資訊等….
瞭解如何在JNI中呼叫Java方法,需要先了解FindClassGetMethodID

FindClass和GetMethodID

在JNI中可以通過FindClass可以找到類,得到jclass,比如:

jclass clz=(*env)->FindClass(env,”com/jjz/JniHandle”);

FindClass的第二個引數需要傳入類的路徑。

使用GetMethodID獲取類的方法,得到jmethodID,比如:

jmethodID getStringFromJava=(*env)->GetMethodID(env,class,”getStringForJava”,”()V”);

如果是靜態函式需要使用GetStaticMethodID獲取靜態函式。
通過FindeClass可以找到JNI需要呼叫的類,GetMethodID可以找到對應的方法,這樣就可以在JNI中呼叫Java的方法了。
在Get
MethodID中,第四個引數是()V,這個是方法簽名。

方法簽名

Get*MethodID的使用中,其中的第四個引數()V就是方法簽名,因為java是支援過載的,所以需要標明函式的傳參和返回值,就是方法的簽名,用來保證方法的唯一。其中()代表不傳引數,V代表返回值為void。
方法簽名對於Java的引數都有一一對應的值。
方法簽名中用大寫的字母對應了java的基本資料型別:

  • Z -> boolean
  • B -> byte
  • C -> char
  • S -> short
  • I -> int
  • J -> long
  • F -> float
  • D -> double

其實就是有兩個比較特殊的:boolean對應的是Z,long對應的J,其他的可以就是首個字母的大寫。

陣列的表示方法,以[為標誌,一個[標識一維陣列,[[表示二維陣列

  • byte[] -> [B
  • int[][] -> [[I

引用型別的表示方法,需要以L開頭,以;結束,中間對應型別的路徑比如:

  • String -> Ljava/lang/String;
  • Object -> Ljava/lang/Object;

自定義的類的表示方法,比如包名為jjz.example,類名為JniHandle:

  • jjz.example.JniHandle ->Ljjz/example/JniHandle;

除了手動輸入類名和方法簽名以外,JDK還提供了直接生成方法簽名的工具javap
到../app/build/intermediates/classes/debug下可以找到build之後生成的.class檔案,執行命令:

javap -s com/jjz/JniHandle

就可以得到類的所有的方法簽名:

靜態函式的呼叫

呼叫類的靜態方法,首先要得到類的引用,再呼叫類的靜態方法。
首先定義一個類和他的靜態方法提供給JNI呼叫:

在JNI中呼叫Java的靜態方法:

這裡需要定義了一個native方法com.jjz.NativeUtil.callJavaStaticMethodFromJni,呼叫該方法可以在logcat中看到結果。

非靜態函式的呼叫

呼叫非靜態函式要複雜一些:

  1. 通過findClass找到類
  2. 通過GetMethodID得到建構函式
  3. 通過呼叫建構函式得到一個類的例項
  4. 通過GetMethodID得到需要呼叫的方法
  5. 使用類的例項呼叫方法

首先定義類的方法:

再定義一個native方法,com.jjz.NativeUtil.callJavaMethodFromJni,在jni中實現該方法:

呼叫方法com.jjz.NativeUtil.callJavaMethodFromJni即可看到Java中的字串傳遞給了JNI輸出到了logcat上。

程式碼中的DeleteLocalRef的意思是釋放區域性引用,VM釋放區域性引用有兩種方法

  • 本地方法執行完畢之後VM自動釋放
  • 通過呼叫DeleteLocalRef手動釋放

既然VM會自動釋放為什麼還要手動釋放呢?
其實區域性變數會阻止它所引用的物件被GC回收,它所引用的物件無法被GC回收,自己本身也就無法被自動釋放,因此需要使用DeleteLocalRef

原始碼地址:https://github.com/jjz/android/tree/master/experimental

相關文章