Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> JNI調用機制

JNI調用機制

編輯:關於Android編程

JNI的簡單介紹   Java Native Interface (JNI)是java本地調用接口,所謂的native就是調用c/c++的程序。 java調用C語言的情況一般有三種: 調用驅動。由於操作系統提供的驅動一般都是C接口,Java語言並不具備操作這些驅動的能力。 對於計算量比較大,處理數據比較多的模塊,java的效率沒有C高,所以希望用C去完成。 對於某些功能模塊,可能Java和C的效率差不多,但是C已經寫好了,就不想用Java重寫了。 從程序的角度來說,主要關注兩種情況: java訪問C C訪問java 對於理解JNI的調用實現,對於理解Android的源碼有幫助,因為Android系統中大量的使用了JIN。   Java訪問C       任何語言直接的交互都必須遵循一定的規則或者協議,只有這樣雙方才能理解各自的意圖。 java中定義native函數,對於native函數只需要聲明,具體實現由C去實現。也就是說,native函數的 實現與聲明是分離的,java負責聲明,C負責實現。所以java在編譯是不會關心具體實現,編譯時就不會出錯。       如何調用的呢?在調用之前java是不會關心是否已經實現,只有在調用native方法的時候,去找C生成的動態庫,如果 找不到動態庫,那麼native方法就會報錯。      java如何找到C的函數的呢?       java的native函數和C中的函數存在一種映射關系,這個映射關系就是遵循的一種協議或者稱為規則。     比如,Framework中AssetManager類中聲明了:          private native final void init()       該方法在C中對應的是:        static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)      從上面的對應關系可以看出,在C中的規則就是,包名+類名+方法名,並且中間用下劃線分割    第一個參數env,是JNIEnv對象,該對象代表一個Java虛擬機所運行的環境,通過它可以訪問JVM內部的各種對象;     第二個參數jobject和是調用該函數的對象,上面的例子指的就是AssetManager對象;每個這樣的C函數的參數至少     有這兩個參數,如果native函數裡有多個參數,依次在後面排列,java的數據類型和JNI中的數據類型對應關系, 自己可以去網上查詢一下。      當java調用native函數時,編譯器會向native引擎傳遞調用者的包名,函數名及參數類型,native引擎 根據這些信息決定應該調用具體的的哪個函數。   在android中,native引擎中的AndroidRuntime類提供了一個registerNativeMethods()函數,通過此函數 定義java方法和C函數的映射關系。   生成 .h文件   java 的native方法和JNI中的c中的函數的對應的定義文件頭文件(.h文件)可以手工寫,有些麻煩 並且還容易出錯,java提供了一個javah工具,通過該工具可以從一個java文件自動生成相應的 投文件,網上查詢一下具體用法。      接下來就是根據頭文件去實現相應的C代碼,然後生成動態庫。   如果想在java中調用native方法,需要使用在調用的代碼前面使用System.loadLibrary("lib_name")去 裝載該動態庫。     C訪問java     雖然C訪問java的情況不多見,不過也是能遇到的。    由於java中的函數在native引擎中並沒有直接的函數指針,java函數只能由java引擎去執行,而不是C。所以訪問 java不能通過指針,只能通過參數接口。    java訪問c的時候,把類名,函數名,參數類型傳遞給native引擎,然後由native引擎處理C函數,同理, C調用java時,也需要把想要訪問的類名、函數名、參數傳遞給java引擎。   按照如下步驟:   獲取java對象的類 jclass cls = env->GetObjectclass(jobject); jobject就是需要調用的誰的方法,java對象在JNI中的表示。 獲得java方法的Id值 jmethodId mid = env->GetMethodId(cls, "method_name", "([Ljava/lang/String;)V"); 第一個參數是java對象對應的類 第二個參數是java中的方法名稱 第三個參數是數據類型和返回值 解釋一下第三個參數: 參數在括弧中,返回值在括弧外, ([Ljava/lang/String;)V" : [Ljava/lang/String代表參數類型,如果是類包名用 “/”分開,並且前面加上又給大寫的L。 java和native數據類型對應表 java類型 native類型 boolean Z byte B char C double D float F int I long L Object 'L' + '包名'+';' short S 這個參數可以自己手工寫,還是那樣容易出錯,java提供了一個工具用來查看參數簽名,使用javap工具可以自動生成,自己從網上查詢一下即可。 調用函數 env->CallXXXMethod(jobject, mid, ret);   其中XXX是不同的類型,包括:Void,Oject,Boolean,Byte,Char,Short,Int,Long,Float,Double 第一個參數是調用的類的對象 第二個參數是上一步獲得的方法的id 第三個參數數是返回值 上面是調用方法,調用java的變量也類似:   獲取java對象的類 jclass cls = env->GetObjectclass(jobject); 獲得變量的id jfiledId fid = env->GetFiledId(cls, "fileName", "I"); 獲取變量值 value = env->GetXXXField(env, jobject, fid);   在C中使用持久對象和保持持久對象    C中本身無法保存持久對象,把持久對象保存到一個int類型的變量上,使用的時候再強制轉型成對象。
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved