編輯:關於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提供了一系列的接口函數,通過這些函數方便地加載虛擬機到內存中。
前陣子要的工作是給桌面(Launcher啟動器,其實也是一個activity)添加一個觸摸特效(一個View),而這個特效是每次觸碰都會有,不管你在桌面上做什麼操作都會顯
在很多的Android項目中都需要用戶登錄、注冊。這樣的話在開發中做好保護用戶密碼的工作就顯得尤為重要。這裡我把自己的密碼保護方法記錄下來。這是我建了一個保存密碼的文件,
首先我發現API還提供一個畫多邊形的類。而一個镂空圓分解成兩個多邊形,即橫著一刀切在這個镂空圓上,上下兩部分各為一個多邊形。但實現上述镂空圓時我的思路還是講經緯度看出笛卡
過濾操作符3.1 filter符合某種規則的Observable才會向下傳遞,例子 Observable.range(100,10).filter(new Fun