編輯:關於Android編程
一:Android系統下JNI簡介
Android系統下的JNI的全稱是:Java Native Interface (JNI),JNI標准是java平台的一部分,它允許Java代碼和其他語言寫的代碼進行交互。JNI 是本地編程接口,它使得在 Java 虛擬機 (VM) 內部運行的 Java 代碼能夠與用其它編程語言(如 C、C++ 和匯編語言)編寫的應用程序和庫進行交互操作。
二:為什麼Java要推出JNI
JNI在Android系統中有著廣泛的應用。Android系統底層都是C/C++實現的,上層提供的API都是Java的,Java通過JNI調用底層的實現。
Java世界虛擬機使用Native語言編寫的,虛擬機運行在具體的平台上,虛擬機本身無法做到與平台無關,jni可以對java層屏蔽不同平台操作的差異,這樣就能實現java本身平台無關特性。適應已經用Native語言實現的技術。一些效率的問題需要Native語言實現。
在Java中使用JNI主要是為了以上幾點而實現的,在Anroid中的API多媒體接口MediaPlayer類,其實底層通過JNI調用libmedia庫。由於JNI的存在可以讓我們重用很多已經存在C/C++的庫,省去了重復開發的麻煩,並且可以利用很多開源的庫(Android庫中就有很多開源庫,比如libjpeg,libpng等等),並且讓我們開發的程序更有效率(C/C++代碼發揮硬件最佳性能)。
三:Java中JNI調用過程
在Java的世界裡,JNI對於應用本身來說,可以看做一個代理模式,對於開始者來說,需要使用C/C++來實現一個代理程序來實際操作目標原生函數,Java程序中則是JVM通過加載並調用JNI程序間接地調用目標原生函數。其調用的示意圖如下:
圖一:Android下JNI調用過程(Load DLL,DLL根據不同的環境而定)
Android系統Java下JNI程序開發的一般操作步驟如下:
編寫JAVA中的調用類;用javah生成C/C++原生函數的頭文件;C/C++中調用需要的其他函數功能,實現原生函數;將項目依賴的所有原生庫和資源加到java項目的路徑中;生成JAVA程序;發布JAVA應用和so庫;
四:Android系統下JNI語法
Android系統Java下的JNI對於應用本身來說,可以看做一個代理模式,對於開始者來說,需要使用C/C++來實現一個代理程序來實際操作目標原生函數,基本的數據類型轉換,如下所示:
圖二:基本數據類型轉換表
備注:符號屬性是指在JNI環境下
引用數據類型轉換表,如下所示:
圖三:引用數據類型轉換表
五:Java下JNI注冊函數
Java下的JNI命名規則:JNI層需要將JAVA函數名稱(包括包名)中的“.”換成“_”,用這種方式可以找到自己JNI層的路徑以及文件。注冊Native函數有兩種方法:靜態注冊和動態注冊。靜態注冊靜態就是根據函數名來建立java和jni函數之間的關聯,而且要求jni層函數的名字必須遵循特定的格式,其缺點在於:需要編譯所有的java聲明的類;javah生成的jni層函數特別長;初次調用native函數時要根據名字搜索對應的jni層函數來建立關聯聯系,這樣影響效率。因此這裡只詳細的講解動態注冊的方式,Java native與JNI通過JNINativeMethod的結構來建立聯系,其結構內容如下:
typedef struce { const char* name; //java中native函數的名字,不用攜帶包的路徑 const char*signature; //java函數的簽名信息,用字符串表示,是參數類型和返回值類型的組合 void *fnptr; //JNI層對應的函數指針,注意他是void*的類型。 } JNINativeMethod;用一個Anroid系統下的實例來感性的認識和說明一下,(請到網上去下載Anroid2.3.4的OK6410的Anroid代碼,跟本文的路徑一致,因為我自己把這個Android2.3.4的OK6410移植到Android2.3.5的平台上)路徑為android2.3.5/frameworksaseservicesorlinx_pwm_jniPwmJniService.cpp,這是一個PWM控制的JNI,具體的如下所示:
圖四:JNINativeMethod方法 Android提供一個RegisterNatives(JNIEnv *env, Const char* className, Const JNINativeMethod* gMethods, int numMethods)來實現這個功能,其實還有一個在AndroidRuntime.cpp中也實現了一個RegisterNatives函數,兩者的功能是相同的,如下所示:
我們來看看PwmJniService.cpp函數中的JNI動態注冊吧,如下所示:
在JNI_OnLoad函數中,會去調用register_forlinx_server_PwmService()這個函數,而這個函數的定義如下所示:
一起來看看這行代碼:static const char* const kClassName =forlinx_pwm_server/server/PwmService;,就是通過kClassName找到相應的庫的,而這個PwmService就是在Android2.3.5/frameworksaseservicesorlinx_pwm_serverserverPwmService.java文件,如下所示:
也就是說Java層通過這種手段實現了Java層去調用C/C++層的庫,這樣就將Anroid底層給封裝起來了,而在Android的JNI層會去調用Android的HAL層,而HAL層調用的就是Linux的驅動!!
六:JNI的垃圾回收
Java中創建的對象最後由垃圾回收器來回收和釋放內存的,而對於JNI,直接對對象進行引用後不會增加引用計數值,當從JNI返回後在JNI引用的對象有可能被垃圾回收器回收,而在JNI下面記錄的指針有可能是野指針,為了解決此類問題,JNI規范提供如下三類引用:
Local Refrence:本地引用,在JNI層函數中使用的非全局變量都是采用Local Refrence,它包含函數調用時傳入的jobject和在JNI層函數中創建的jobject,其最大的特點是一旦JNI層函數返回,這些jobject就可能被垃圾回收了。Global Refrence:全局引用,這類引用如果程序不主動調用銷毀接口將一直駐留在內存中。Weak Global Refrence:弱全局引用,在使用過程中有可能被釋放,調用JNIEnv中IsSameObject函數來判斷是否仍然存在。 七:Java下JNI函數的簽名信息 Android系統下Jave的JNI的簽名Signature的書寫規則如下: ()中的字符表示參數,後面的則代表返回值,如“()V”就表示void func(), “(II)V”表示void func(int, int)等。具體的每個字符對應關系如下:
Ljava/lang/String; String jstring Ljava/net/Socket; Socket jobject以android2.3.5/frameworksaseservicesorlinx_pwm_jniPwmJniService.cpp中的static const JNINativeMethod gMethods[]數組函數為例子,如下所示:
最近項目上需要實現藍牙傳輸apk的一個功能,能夠搜索周圍的藍牙手機並分享文件。從需求上講android手機自帶的藍牙傳輸模塊就可以滿足需要了,實現也很簡單。不過讓人頭疼的
AChartEngine是一個很強大的圖表引擎,我在上學的時候就接觸過,並且利用它做了一個傳感器的應用,想想現在也很久遠了,今天就把這個app的源碼貼出來供其他人研究這款
由於在android studio剛推出市場的時候,我已有下載和體驗,當時的studio界面相對簡單,沒有在1.3或1.2版本的密集的功能點,而且但是使用studio還蠻
昨天想要實現一個下拉刷新的效果,本來想應該比較簡單,因為之前在慕課網看見過類似的實現,記得是在listView裡面添加footView或是添加headView,監聽手指的