Android JNI調用(一)

  1.jni的基本工作原理  
       (1)java的本質

  想搞明白jni的本質,還要從java的本質說起.從本質上來說,java這門語言就是一門腳本語言(這是偶的個人理解,希望java大俠們不要用板磚拍我),它的運行完全依賴於腳本引擎對java的代碼進行解釋和執行(當然了,現代的java已經先進許多,可以從源代碼編譯成.class之類的中間格式的二進制文件,這種處理會大大地加快java腳本的運行速度,但是基本的執行方式仍然不變,由腳本引擎(我們稱之爲JVM)來執行,與python、perl之類的純腳本相比,它只是把腳本變成了二進制格式而已.另外就是java本身對面向對象的概念支持得很好,擁有完善的功能庫可供調用,把這個腳本引擎移植到所有平臺上,那麼這個腳本自然就實現所謂的“跨平臺”了).絕大多數的腳本引擎都支持一個很顯著的特性,就是可以通過c/c++編寫模塊,在腳本中調用這些模塊,以此來類比java,也是一樣的,java一定要提供一種在腳本中調用c/c++編寫的模塊的機制,才能稱得上是一個相對完善的腳本引擎.

  (2)android中的java

  android平臺從本質上是 由arm-linux操作系統 和一個叫做dalvik的java虛擬機組成的.所有在android模擬器上面看到的那些華麗的界面,都是用java語言編寫的(參見android平臺源代碼的frameworks/base目錄).目前看來dalvik只是提供了一個標準的支持jni調用的java虛擬機環境.android平臺中所有的硬件相關的操作均是採用jni技術進行了封裝,由java去調用jni模塊,而jni模塊使用c/c++調用android本身的arm-linux底層驅動.

  例如,frameworks/base/libs/ui目錄下面有一個叫做“EGLDisplaySurface.cpp”的文件,裏面的:

  status_t EGLDisplaySurface::mapFrameBuffer()函數中,就有直接對android的arm-linux中的framebuffer的初始化代碼.

  這也更加印證了,android其實是依靠java+jni建立起來的王國.hoho,如此一來,就凸顯出jni在Android開發中的重要性(當然,一些簡單的小程序是完全可以只用java就搞定的).

  “jni”的子目錄,這個目錄將用來存放.c的文件.

  (3)編寫jni模塊的java調用類

  這是必然的了,jni嘛,一定要有調用者才能夠工作在src的最內層目錄裏面添加一個叫做JniModule.java的原文件,看上去如下所示:

java代碼:
  1. public class JniModule {

  2. static {
  3. System.loadLibrary("aaaa") ; 
  4. }
  5. public native static int jni_add(int a, int b) ; 
  6. }
複製代碼

       注意,偶們最終會生成一個叫做libaaaa.so的arm兼容的二進制動態庫,但是在使用System.loadLibrary動態載入的時候,只需要填寫lib和.so之間的名字aaaa即可,在此實驗的功能僅僅是兩個數字a和b的求和計算以及如何在jni的c語言模塊中把log日誌打印到logcat中.

        在JniTest.java中,偶們可以如下調用這個類:

java代碼:
  1. public void onClick(View v) {

  2. String ss ; 
  3. int a = 3 ; 
  4. int b = 4 ; 

  5. ss = "" ; 
  6. switch(v.getId()) {
  7. case R.id.button1:
  8. ss = "a="+String.valueOf(a)+","+"b=" + String.valueOf(b) + "," + "a+b=" + 
  9. String.valueOf(JniModule.jni_add(a, b)); 

  10. setTitle(ss) ;

  11. break ; 
  12. case R.id.button2:
  13. setTitle("button2 click") ; 
  14. break ; 
  15. case R.id.button3:
  16. int pid = android.os.Process.myPid(); 
  17. android.os.Process.killProcess(pid);
  18. break ; 


  19. }

複製代碼

       注意,這裏的button3是很重要的,功能是得到當前程序的進程id,然後顯示地殺掉它!
       爲什麼要這麼做呢?原因在於,android裏面的常規退出函數並沒有真正地關閉當前運行的進程,而是切換到後臺去了。這對普通的java應用看上去很平常,而且可以加速再次啓動該程序的速度,但是對於帶有jni模塊的java程序而言就是惡夢,因爲程序沒有真的關閉。所以那個libaaaa.so庫,會一直停留在內存中,這時候如果你希望把舊的so庫替換成新的庫,那就要重啓手機才行。。。很痛苦,所以想到了這種辦法,直接殺掉自己,那麼下一次啓動的時候就會自動重新載入最新的so庫。
發佈了71 篇原創文章 · 獲贊 30 · 訪問量 60萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章