帶著問題入場:
- 什么是JNI,NDK, 與Java是什么關(guān)系,有什么應(yīng)用場景?
- JNI提供了哪些基本數(shù)據(jù)類型徽诲?
接下來會針對這兩個問題森瘪,一一道來牡属。
-
什么是JNI, NDK, 有什么應(yīng)用場景?
JNI是Oracle提供的用于Java調(diào)用C/C++或C/C++調(diào)用Java的一套機(jī)制, 有自己的一套API扼睬,并且與C/C++或者匯編混合使用JNI逮栅,Java Native Interface,是 native code 的編程接口窗宇。JNI 使 Java 代碼程序可以與 native code 交互——在 Java 程序中調(diào)用 native code措伐;在 native code 中嵌入 Java 虛擬機(jī)調(diào)用 Java 的代碼。
NDK提供了一系列的工具军俊,幫助開發(fā)者快速開發(fā)C(或C++)的動態(tài)庫侥加,并能自動將so和java應(yīng)用一起打包成apk。這些工具對開發(fā)者的幫助是巨大的粪躬。
NDK集成了交叉編譯器担败,并提供了相應(yīng)的mk文件隔離CPU、平臺镰官、ABI等差異提前,開發(fā)人員只需要簡單修改mk文件(指出"哪些文件需要編譯"、"編譯特性要求"等)泳唠,就可以創(chuàng)建出so.
NDK可以自動地將so和Java應(yīng)用一起打包狈网,極大地減輕了開發(fā)人員的打包工作.
-
應(yīng)用場景:
- 可以將要求高性能的應(yīng)用邏輯使用C開發(fā),從而提高應(yīng)用程序的執(zhí)行效率
- 可以將需要保密的應(yīng)用邏輯使用C開發(fā)笨腥。畢竟孙援,Java包都是可以反編譯的
- 之前C/C++語言開發(fā)的基礎(chǔ)功能模塊復(fù)用到Android JNI環(huán)境下。
-
JNI提供了哪些基本數(shù)據(jù)類型扇雕,提供了哪些API拓售?
-
JNI基本數(shù)據(jù)類型與Java數(shù)據(jù)類型的對應(yīng)關(guān)系
basic_type_sign.png -
JNI引用類型與Java數(shù)據(jù)類型的對應(yīng)關(guān)系
reference_type.png -
提供的特有的類, jfieldID, jmethodID, JNIEnv等
jfielID 是JNI提供的JNI 字段類
jmethodID 是JNI提供的JNI方法類
JNIEnv是JNI 接口的全局指針類镶奉,類似于JNI的上下文對象
-
Global and Local References
為啥會用到這兩類引用础淤?先說LocalReference,比如平時通過New操作得到的引用類型的對象崭放,都屬于Local Reference,看上去像是一個局部變量鸽凶,其實(shí)不是币砂,它與局部變量有這本質(zhì)區(qū)別,在用完變量后需要手動釋放玻侥,而局部變量卻不需要决摧。
Global Reference 是全局的引用,在New Global后一定要Release 這個全局引用凑兰。
關(guān)于這兩類引用的使用過程中如何進(jìn)行內(nèi)存管理掌桩,在"JNI內(nèi)存管理模型”中會詳細(xì)描述。
-
提供哪幾類API姑食,作用分別是什么波岛?
-- 類操作 FindClass()
-- 全局引用與局部引用相關(guān)操作NewGlobalRef() DeleteGlobalRef() NewWeakGlobalRef() DeleteWeakGlobalRef() NewLocalRef() DeleteLocalRef()
-- 對象操作 不知道有什么用?
-- 訪問對象的成員
GetFieldID() Get<type>Field() 先拿fieldID,在獲取字段值
Set<type>Field()-- 訪問靜態(tài)成員
GetStaticFieldID()
GetStatic<type>Fiel SetStatic<type>Field
-- 對象成員函數(shù)調(diào)用
GetMethodID()
Call<type>Method
Call<type>MethodA
Call<type>MethodV
CallNonvirtual<type>Method
CallNonvirtual<type>MethodA
CallNonvirtual<type>MethodV
-- 靜態(tài)函數(shù)調(diào)用
GetStaticMethodID()
CallStatic<type>Method
CallStatic<type>MethodA
CallStatic<type>MethodV
-- 字符串操作
NewString() NewStringUTF()
GetStringLength()
GetStringChars()
ReleaseStringChars()
GetStringUTFLength()
GetStringUTFChars()
ReleaseStringUTFChars()
GetStringRegion()
GetStringUTFRegion()
-- 數(shù)組操作
GetArrayLength()
NewObjectArray(JNIEnv *env, jsize length,jclass elementClass, jobject initialElement);
jobject GetObjectArrayElement()
SetObjectArrayElement()基本數(shù)據(jù)類型的數(shù)組操作 New<PrimitiveType>Array() Get<PrimitiveType>ArrayElements() Release<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, NativeType *elems, jint mode) 參數(shù)對應(yīng)關(guān)系圖 void Get<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array,jsize start, jsize len, NativeType *buf); void Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array,jsize start, jsize len, const NativeType *buf)
-- 函數(shù)注冊于反注冊
jint RegisterNatives(JNIEnv *env, jclass clazz,const JNINativeMethod *methods, jint nMethods);
jint UnregisterNatives(JNIEnv *env, jclass clazz);
-- 反射函數(shù) 還不知道如何使用
jmethodID FromReflectedMethod(JNIEnv *env, jobject method);
jfieldID FromReflectedField(JNIEnv *env, jobject field);
jobject ToReflectedMethod(JNIEnv *env, jclass cls,jmethodID methodID, jboolean isStatic);
jobject ToReflectedField(JNIEnv *env, jclass cls,jfieldID fieldID, jboolean isStatic); -
JNI 類型簽名
-
基本數(shù)據(jù)類型的類型簽名
basic_type_sign.png-
引用數(shù)據(jù)類型的類型簽名
reference_type_sign.png
-
方法的描述符
-
-
-
JNI Exception
三個函數(shù)ExceptionOccured()音半,ExceptionClear()则拷,ThrownNew()。
首先使用ExceptionOccured()函數(shù)判斷是否發(fā)生異常曹鸠,如果發(fā)生異常煌茬,可以在JNI處理也可以通過ThrowNew將異常拋出到Java層處理。但是在實(shí)際的使用中發(fā)現(xiàn)JNI的Exception有兼容性問題彻桃,不推薦使用宣旱。