NDK開發 從入門到放棄(四:JNI函式、C與C++呼叫函式的區別)
前言
在之前的文章中我們看到過如下C++程式碼:
jclass clazz = env->FindClass("***/***/JNIDynamicUtils");
FindClass
就屬於jni函式。此文就來稍微講解下一些常用的jni函式。
C與C++呼叫函式的區別
如上述程式碼,則是C++檔案內的程式碼。標準的C實現上述程式碼的方式是:
jclass clazz = (*env)->FindClass(env, "***/***/JNIDynamicUtils");
看到不同的表示方式便能知道寫的是C還是C++了。相比較的話,C++程式碼還是簡潔一些。
JNI函式
以下為部分入門級函式,後續會不斷補充。
1. FindClass
jclass FindClass(JNIEnv *env, const char *name);
該函式用於載入本地定義的類。
引數:
env:JNI介面指標。下面將不再介紹 ,在C++程式碼中,引數不傳該值。
name:類全名(即包名後跟類名,之間由“/”分隔)。如果該名稱以“[”(陣列簽名字元)打頭,則返回一個數組類。
返回值:
返回類物件全名。如果找不到該類,則返回NULL。
丟擲:
ClassFormatError:如果類資料指定的類無效。
ClassCircularityError:如果類或介面是自身的超類或超介面。
NoClassDefFoundError:如果找不到所請求的類或介面的定義。
OutOfMemoryError:如果系統記憶體不足。
2. GetMethodID
jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
返回類或介面例項(非靜態)方法的方法ID。方法可在某個clazz的超類中定義,也可從clazz繼承。該方法由其名稱和簽名決定。GetMethodID()
可使未初始化的類初始化。要獲得建構函式的方法ID,應將<init>
作為方法名,同時將()V
作為返回型別。
引數:
clazz:Java類物件。
name:0終結的UTF-8字串中的方法名。
sig:0終結的UTF-8字串中的方法簽名。
返回值:
方法ID,如果找不到指定的方法,則為NULL。
丟擲:
NoSuchMethodError:如果找不到指定方法。
ExceptionInInitializerError:如果由於異常而導致類初始化程式失敗。
OutOfMemoryError:如果系統記憶體不足。
3. NewObject
jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...);
構造新Java物件。方法ID必須通過呼叫GetMethodID()
獲得,為應呼叫的建構函式方法。clazz引數務必不要引用陣列類。
引數:
clazz:Java類物件。
methodID:建構函式的方法ID。
其它引數:傳給建構函式的引數。
返回值:
返回Java物件,如果無法構造該物件,則返回NULL。
丟擲:
InstantiationException:如果該類為介面或抽象類。
OutOfMemoryError:如果系統記憶體不足。
其他:建構函式丟擲的任何異常。
4. NewStringUTF
jstring NewStringUTF(JNIEnv *env, const char *bytes);
利用UTF-8字元陣列構造新java.lang.String物件。
引數:
bytes:指向UTF-8字串的指標。
返回值:
Java字串物件。如果無法構造該字串,則為NULL。
丟擲:
OutOfMemoryError:如果系統記憶體不足。
5. GetStringUTFLength
jsize GetStringUTFLength(JNIEnv *env, jstring string);
以位元組為單位返回字串的UTF-8長度。
引數:
string:Java字串物件。
返回值:
返回字串的UTF-8長度。若引數為null,則會異常。
6. Throw
jint Throw(JNIEnv *env, jthrowable obj);
丟擲java.lang.Throwable異常物件。
引數:
obj:java.lang.Throwable物件。
返回值:
成功時返回0,失敗時返回負數。
丟擲:
java.lang.Throwable物件obj。
tip:
與java不同,丟擲異常後,後續程式碼還會繼續執行,直至return。
7. ThrowNew
jint ThrowNew(JNIEnv *env, jclass clazz, const char *message);
利用指定類的訊息(由message指定)構造異常物件並丟擲該異常。
引數:
clazz:java.lang.Throwable的子類。
message:用於構造java.lang.Throwable物件的訊息。
返回值:
成功時返回0,失敗時返回負數。
丟擲:
新構造的java.lang.Throwable物件。
8. GetArrayElements
NativeType *Get<PrimitiveType>ArrayElements (JNIEnv *env, ArrayType array, jboolean*isCopy);
一組返回基本型別陣列體的函式。結果在呼叫相應的ReleaseArrayElements()函式前將一直有效。由於返回的陣列可能是Java陣列的副本,因此對返回陣列的更改不必在基本型別陣列中反映出來,直到呼叫了 ReleaseArrayElements()。如果isCopy不是NULL,*isCopy在複製完成後即被設為JNI_TRUE。如果未複製,則設為JNI_FALSE。
GetArrayElements例程 | 陣列型別 | 本地型別 |
---|---|---|
GetBooleanArrayElements() | jbooleanArray | jboolean |
GetByteArrayElements() | jbyteArray | jbyte |
GetCharArrayElements() | jcharArray | jchar |
GetShortArrayElements() | jshortArray | jshort |
GetIntArrayElements() | jintArray | jint |
GetLongArrayElements() | jlongArray | jlong |
GetFloatArrayElements() | jfloatArray | jfloat |
GetDoubleArrayElements() | jdoubleArray | jdouble |
引數:
array:Java字串物件。
isCopy:指向布林值的指標。
返回值:
返回指向陣列元素的指標,如果操作失敗,則為NULL。
9. ReleaseArrayElements
void Release<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, NativeType *elems, jint mode);
通知虛擬機器平臺相關程式碼無需再訪問elems的一組函式。elems引數是一個通過使用對應的GetArrayElements()
函式由array匯出的指標。必要時,該函式將把對elems的修改複製回基本型別陣列。mode引數將提供有關如何釋放陣列緩衝區的資訊。 如果elems不是array中陣列元素的副本,mode將無效。否則,mode將具有下表所述的功能:
基本型別陣列釋放模 | 動作 |
---|---|
0 | 複製回內容並釋放elems緩衝區 |
JNI_COMMIT | 複製回內容但不釋放elems緩衝區 |
JNI_ABORT | 釋放緩衝區但不復制回變化 |
多數情況下,程式設計人員將把“0”傳給mode引數以確保固定的陣列和複製的陣列保持一致。其它選項可以使程式設計人員進一步控制記憶體 管理,但使用時務必慎重。
引數:
array:Java陣列物件。
elems:指向陣列元素的指標。
mode:釋放模式。
10. NewArray
ArrayType New<PrimitiveType>Array(JNIEnv *env, jsize length);
用於構造新基本型別陣列物件的一系列操作。下表說明了特定的基本型別陣列建構函式。使用者應把NewArray替換為 某個實際的基本型別陣列建構函式例程名(見下表),然後將ArrayType替換為該例程相應的陣列型別。
NewArray例程 | 陣列型別 |
---|---|
NewBooleanArray() | jbooleanArray |
NewByteArray() | jbyteArray |
NewCharArray() | jcharArray |
NewShortArray() | jshortArray |
NewIntArray() | jintArray |
NewLongArray() | jlongArray |
NewFloatArray() | jfloatArray |
NewDoubleArray() | jdoubleArray |
引數:
length:陣列長度。
返回值:
Java陣列。如果無法構造該陣列,則為NULL。
11. SetArrayRegion
void Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, NativeType *buf);
將基本型別陣列的某一區域從緩衝區中複製回來的一組函式。下表說明了特定的基本型別陣列元素訪問器。應進行如下替換:
SetArrayRegion例程 | 陣列型別 | 本地型別 |
---|---|---|
SetBooleanArrayRegion() | jbooleanArray | jboolean |
SetByteArrayRegion() | jbyteArray | jbyte |
SetCharArrayRegion() | jcharArray | jchar |
SetShortArrayRegion() | jshortArray | jshort |
SetIntArrayRegion() | jintArray | jint |
SetLongArrayRegion() | jlongArray | jlong |
SetFloatArrayRegion() | jfloatArray | jfloat |
SetDoubleArrayRegion() | jdoubleArray | jdouble |
引數:
array: Java陣列。
start:起始下標。
len:要複製的元素數。
buf:源緩衝區。
丟擲:
ArrayIndexOutOfBoundsException:如果區域中的某個下標無效。