Android JNI必須掌握的五點

來源:互聯網
上載者:User

1:JNI是什嗎?

 

Java NativeInterface(JNI)是Java提供的一個很重要的特性。它使得用諸如C/C++等語言編寫的代碼可以與運行於Java虛擬機器(JVM)中的 Java代碼整合。有些時候,Java並不能滿足你的全部開發需求,比如你希望提高某些關鍵模組的效率,或者你必須使用某個以C/C++等Native語 言編寫的程式庫;此時,JNI就能滿足你在Java代碼中訪問這些Native模組的需求。JNI的出現使得開發人員既可以利用Java語言跨平台、類庫豐 富、開發便捷等特點,又可以利用Native語言的高效。

 

2:JNI和JVM什麼關係?

JNI是JVM實現中的一部分,因此Native語言和Java代碼都運行在JVM的宿主環境(Host Environment)。此外,JNI是一個雙向的介面:開發人員不僅可以通過JNI在Java代碼中訪問Native模組,還可以在 Native代碼中嵌入一個JVM,並通過JNI訪問運行於其中的Java模組。可見,JNI擔任了一個橋樑的角色,它將JVM與Native模組聯絡起來,從而實現了Java代碼與Native代碼的互訪。在OPhone上使用Java虛擬機器是為嵌入式裝置特別最佳化的Dalvik虛擬機器。每啟動一個應 用,系統會建立一個新的進程運行一個Dalvik虛擬機器,因此各應用實際上是運行在各自的VM中的。Dalvik VM對JNI的規範支援的較全面,對於從JDK 1.2到JDK 1.6補充的增強功能也基本都能支援。

 

開發人員在使用JNI之前需要充分瞭解其優缺點,以便合理選擇技術方案實現目標。JNI的優點前面已經講過,這裡不再重複,其缺點也是顯而易見的:由於Native模組的使用,Java代碼會喪失其原有的跨平台性和型別安全等特性。此外,在JNI應用中,Java代碼與Native代碼運行於同一個進程空間內;對於跨進程甚至跨宿主環境的Java與Native間通訊的需求,可以考慮採用socket、Web Service等IPC通訊機制來實現。

 

 

3:JNI在JAVE和c++中互通性;

     a:java和c++的基本調用:

 

     b:JNIhelper的概念和用法:

 就是編譯的時候,會出現編譯的error,想調試的哥們,try一下;問題不大;

     c:獨立JNIhelper的使用:

 

 

4:JNI的編譯

 

     Android.mk的編譯配置:

  

 

     編譯的基本命令:

 

 

 

5: JNI用法品讀

 

   (1).andorid CPP調用java函數和訪問其成員:

原理 => CPP代碼找到java的那個class裡面的函數的入口地址,然後在CPP代碼中調用java代碼

 

步驟1) 用FindClass()函數找到該java類(如android.os.Binder)的執行個體對象的引用:

  jclass clazz =env->FindClass(kBinderPathName) =env->FindClass("android.os.Binder")

 

步驟2) 用GetFieldID()函數擷取到要訪問的域(field: 實際上就是該java class中的某個成員變數的名字)的ID:

  gBinderOffsets.mObject= env->GetFieldID(clazz, "mObject", "I") // mObject為java class "Binder"裡的一個成員變數

  -> 注意,這裡將要訪問的那個java對象的成員mObject的ID儲存到了全域變數gBinderOffsets.mObject中,這樣做的前提和優點如下:

  前提: android裡面,每個java進程中只允許有一個java虛擬機器(sun公司原始的java架構中,一個進程中可以有多個java虛擬機器)

  優點: 除了第一次,以後每次要訪問該java對象的成員mObject就非常快了(不用再去FindClass()和GetFieldID())

 

步驟3) 用GetMethodID()函數擷取到要訪問的方法(Method: 實際上就是該java class中的某個成員函數的名字)的ID:

  gBinderOffsets.mExecTransact= env->GetMethodID(clazz, "execTransact", "(IIII)Z") //execTransact為java class "Binder"裡的一個成員函數

 

步驟4) 用類似於GetIntField()的函數擷取到該java對象的那個域(即成員)的值:

  IBinder* target =(IBinder*)env->GetIntField(obj,gBinderProxyOffsets.mObject)

    // 擷取javaandroid.os.Binder類型對象裡面的成員mObject的值


步驟5) 用類似於CallBooleanMethod()的函數調用到該java對象的那個成員函數:

  jboolean res =env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, code,(int32_t)&data, (int32_t)reply, flags)

 

(2).android java調用CPP函數:

 

原理 => 相當於java的那個class裡面有的函數使用CPP代碼來實現了

1)通過結構JNINativeMethod描述java代碼調用函數和CPP函數的對應關係:

  typedef struct {

  const char* name; //java代碼調用CPP函數的入口

  const char*signature; // CPP函數的傳回值

  void* fnPtr; // CPP的函數名

  } JNINativeMethod;

  => 例如: java代碼通過IBinder.transact()來調用CPP的函數android_os_BinderProxy_transact()

  {"transact","(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z",(void*)android_os_BinderProxy_transact},

 

2)將CPP函數註冊到java的某個class中: 使用函數AndroidRuntime::registerNativeMethods()來註冊

  => 這之後,java代碼就可以調用CPP函數了

 

3)java代碼調用CPP函數方法:

  IBinder.transact()

 

總結其原理:C/C++要調用JAVA程式,必須先載入JAVA虛擬機器,由JAVA虛擬機器解釋執行class檔案。為了初始化JAVA虛擬機器,JNI提供了一系列的介面函數,通過這些函數方便地載入虛擬機器到記憶體中。    

    

    

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.