Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android JNI必須掌握的五點

Android JNI必須掌握的五點

編輯:關於Android編程

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提供了一系列的接口函數,通過這些函數方便地加載虛擬機到內存中。    

    

    

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved