国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Android - Android中的JNI數組操作教程

Android中的JNI數組操作教程

2022-03-10 15:11紙上淺談 Android

這篇文章主要給大家介紹了關于Android中JNI數組操作的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

JNI 中有兩種數組操作,基礎數據類型數組和對象數組,JNI 對待基礎數據類型數組和對象數組是不一樣的。

基本數據類型數組

對于基本數據類型數組,JNI 都有和 Java 相對應的結構,在使用起來和基本數據類型的使用類似。

在 Android JNI 基礎知識篇提到了 Java 數組類型對應的 JNI 數組類型。比如,Java int 數組對應了 jintArray,boolean 數組對應了 jbooleanArray。

如同 String 的操作一樣,JNI 提供了對應的轉換函數:GetArrayElements、ReleaseArrayElements。

?
1
2
intArray = env->GetIntArrayElements(intArray_, NULL);
env->ReleaseIntArrayElements(intArray_, intArray, 0);

另外,JNI 還提供了如下的函數:

GetTypeArrayRegion / SetTypeArrayRegion

將數組內容復制到 C 緩沖區內,或將緩沖區內的內容復制到數組上。

GetArrayLength

得到數組中的元素個數,也就是長度。

NewTypeArray

返回一個指定數據類型的數組,并且通過 SetTypeArrayRegion 來給指定類型數組賦值。

GetPrimitiveArrayCritical / ReleasePrimitiveArrayCritical

如同 String 中的操作一樣,返回一個指定基礎數據類型數組的直接指針,在這兩個操作之間不能做任何阻塞的操作。

實際操作如下:

?
1
2
// Java 傳遞 數組 到 Native 進行數組求和
private native int intArraySum(int[] intArray, int size);

對應的 C++ 代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
JNIEXPORT jint JNICALL
Java_com_glumes_cppso_jnioperations_ArrayTypeOps_intArraySum(JNIEnv *env, jobject instance,
        jintArray intArray_, jint num) {
 jint *intArray;
 int sum = 0;
 // 操作方法一:
 // 如同 getUTFString 一樣,會申請 native 內存
 intArray = env->GetIntArrayElements(intArray_, NULL);
 if (intArray == NULL) {
 return 0;
 }
 // 得到數組的長度
 int length = env->GetArrayLength(intArray_);
 LOGD("array length is %d", length);
 for (int i = 0; i < length; ++i) {
 sum += intArray[i];
 }
 LOGD("sum is %d", sum);
 
 // 操作方法二:
 jint buf[num];
 // 通過 GetIntArrayRegion 方法來獲取數組內容
 env->GetIntArrayRegion(intArray_, 0, num, buf);
 sum = 0;
 for (int i = 0; i < num; ++i) {
 sum += buf[i];
 }
 LOGD("sum is %d", sum);
 // 使用完了別忘了釋放內存
 env->ReleaseIntArrayElements(intArray_, intArray, 0);
 return sum;
}

假如需要從 JNI 中返回一個基礎數據類型的數組,對應的代碼如下:

?
1
2
// 從 Native 返回基本數據類型數組
private native int[] getIntArray(int num);

對應的 C++ 代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * 從 Native 返回 int 數組,主要調用 set<Type>ArrayRegion 來填充數據,其他數據類型類似操作
 */
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_glumes_cppso_jnioperations_ArrayTypeOps_getIntArray(JNIEnv *env, jobject instance,
        jint num) {
 jintArray intArray;
 intArray = env->NewIntArray(num);
 
 jint buf[num];
 for (int i = 0; i < num; ++i) {
 buf[i] = i * 2;
 }
 
 // 使用 setIntArrayRegion 來賦值
 env->SetIntArrayRegion(intArray, 0, num, buf);
 return intArray;
}

以上例子,基本把相關的操作都使用上了,可以發現和 String 的操作大都是相似的。

對象數組

對于對象數組,也就是引用類型數組,數組中的每個類型都是引用類型,JNI 只提供了如下函數來操作。

GetObjectArrayElement / SetObjectArrayElement

和基本數據類型不同的是,不能一次得到數據中的所有對象元素或者一次復制多個對象元素到緩沖區。只能通過上面的函數來訪問或者修改指定位置的元素內容。

字符串和數組都是引用類型,因此也只能通過上面的方法來訪問。

例如在 JNI 中創建一個二維的整型數組并返回:

?
1
2
// 從 Native 返回二維整型數組,相當于是一個一維整型數組,數組中的每一項內容又是數組
private native int[][] getTwoDimensionalArray(int size);

二維數組具有特殊性在于,可以將它看成一維數組,其中數組的每項內容又是一維數組。

具體 C++ 代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
 * 從 Native 返回一個二維的整型數組
 */
extern "C"
JNIEXPORT jobjectArray JNICALL
Java_com_glumes_cppso_jnioperations_ArrayTypeOps_getTwoDimensionalArray(JNIEnv *env,
         jobject instance,
         jint size) {
 // 聲明一個對象數組
 jobjectArray result;
 // 找到對象數組中具體的對象類型,[I 指的就是數組類型
 jclass intArrayCls = env->FindClass("[I");
 
 if (intArrayCls == NULL) {
 return NULL;
 }
 // 相當于初始化一個對象數組,用指定的對象類型
 result = env->NewObjectArray(size, intArrayCls, NULL);
 
 if (result == NULL) {
 return NULL;
 }
 for (int i = 0; i < size; ++i) {
 // 用來給整型數組填充數據的緩沖區
 jint tmp[256];
 // 聲明一個整型數組
 jintArray iarr = env->NewIntArray(size);
 if (iarr == NULL) {
  return NULL;
 }
 for (int j = 0; j < size; ++j) {
  tmp[j] = i + j;
 }
 // 給整型數組填充數據
 env->SetIntArrayRegion(iarr, 0, size, tmp);
 // 給對象數組指定位置填充數據,這個數據就是一個一維整型數組
 env->SetObjectArrayElement(result, i, iarr);
 // 釋放局部引用
 env->DeleteLocalRef(iarr);
 }
 return result;
}

首先需要使用 NewObjectArray 方法來創建對象數組。

然后使用 SetObjectArrayElement 函數填充數據時,需要構建好每個位置對應的對象。這里就使用了 NewIntArray 來創造了一個對象,并給對象填充數據后,在賦值給對象數組。

通過一個 for 循環就完成給對象數組賦值的操作。

在創建對象數組時,有一個操作是找到對應的對象類型,通過 findClass 方法。findClass 的參數 [I 這里就涉及到 Java 與 JNI 對應簽名的轉換。

Java 與 JNI 簽名的轉換

在前一篇文章中,用表格列出了 Java 與 JNI 對應的數據類型格式的轉換關系,現在要列舉的是 Java 與 JNI 對應簽名的轉換關系。

這里的簽名指的是在 JNI 中去查找 Java 中對應的數據類型、對應的方法時,需要將 Java 中的簽名轉換成 JNI 所能識別的。

對于類的簽名轉換

對于 Java 中類或者接口的轉換,需要用到 Java 中類或者接口的全限定名,把 Java 中描述類或者接口的 . 換成 / 就好了,比如 String 類型對應的 JNI 描述為:

?
1
java/lang/String // . 換成 /

對于數組類型,則是用 [ 來表示數組,然后跟一個字段的簽名轉換。

?
1
2
3
[I   // 代表一維整型數組,I 表示整型
[[I  // 代表二維整型數組
[Ljava/lang/String;  // 代表一維字符串數組,

對于字段的簽名轉換

對應基礎類型字段的轉換:

 

Java 類型 JNI 對應的描述轉
boolean Z
byte B
char C
short S
int I
long J
float F
double D

 

對于引用類型的字段簽名轉換,是大寫字母 L 開頭,然后是類的簽名轉換,最后以 ; 結尾。

 

Java 類型 JNI 對應的描述轉換
String Ljava/lang/String;
Class Ljava/lang/Class;
Throwable Ljava/lang/Throwable
int[] "[I"
Object[] "[Ljava/lang/Object;"

 

對于方法的簽名轉換

對于方法簽名描述的轉換,首先是將方法內所有參數轉換成對應的字段描述,并全部寫在小括號內,然后在小括號外再緊跟方法的返回值類型描述。

 

Java 類型 JNI 對應的描述轉換
String f(); ()Ljava/lang/String;
long f(int i, Class c); (ILjava/lang/Class;)J
String(byte[] bytes); ([B)V

 

這里要注意的是在 JNI 對應的描述轉換中不要出現空格。

了解并掌握這些轉換后,就可以進行更多的操作了,實現 Java 與 C++ 的相互調用。

比如,有一個自定義的 Java 類,然后再 Native 中打印類的對象數組的某一個字段值。

?
1
private native void printAnimalsName(Animal[] animal);

具體 C++ 代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
 * 打印對象數組中的信息
 */
extern "C"
JNIEXPORT void JNICALL
Java_com_glumes_cppso_jnioperations_ArrayTypeOps_printAnimalsName(JNIEnv *env, jobject instance,
                 jobjectArray animals) {
 jobject animal;
 // 數組長度
 int size = env->GetArrayLength(animals);
 // 數組中對應的類
 jclass cls = env->FindClass("com/glumes/cppso/model/Animal");
 // 類對應的字段描述
 jfieldID fid = env->GetFieldID(cls, "name", "Ljava/lang/String;");
 // 類的字段具體的值
 jstring jstr;
 // 類字段具體值轉換成 C/C++ 字符串
 const char *str;
 
 for (int i = 0; i < size; ++i) {
  // 得到數組中的每一個元素
  animal = env->GetObjectArrayElement(animals, i);
  // 每一個元素具體字段的值
  jstr = (jstring) (env->GetObjectField(animal, fid));
  str = env->GetStringUTFChars(jstr, NULL);
  if (str == NULL) {
   continue;
  }
  LOGD("str is %s", str);
  env->ReleaseStringUTFChars(jstr, str);
 }
}

具體示例代碼可參考我的 Github 項目,歡迎 Star。

https://github.com/glumes/AndroidDevWithCpp

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://segmentfault.com/a/1190000015542628

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美日韩视频在线 | 亚洲视频黄 | 视频在线一区二区 | 国产成人精品久久 | 久久66 | 亚洲国产高清在线 | 国产综合精品一区二区三区 | 成人精品国产免费网站 | 国产亚洲欧美另类一区二区三区 | 亚洲欧美一区二区三区情侣bbw | 中文二区 | 日韩精品专区在线影院重磅 | 国产乱码精品一品二品 | 国产精品久久久久久久午夜片 | 日韩一区二区三区在线观看 | 国产欧美精品一区二区 | 成人亚洲 | www.久草 | 亚洲国产精品99久久久久久久久 | 黄色一级毛片在线观看 | 午夜资源 | 国产精品久久久久久久久久久久久久久久 | 国产亲子乱弄免费视频 | 一区二区观看 | 国产精品手机在线 | 在线看一区 | 欧美一区二区三区视频在线 | 夜操| 成人在线视频网站 | 国内精品嫩模av私拍在线观看 | 国精产品99永久一区一区 | 国产精品99久久久久久动医院 | 国产精品永久免费自在线观看 | 在线精品国产一区二区三区 | 亚洲一区二区三区在线免费观看 | 中文字幕久久网 | 成年人在线免费观看视频网站 | 欧美激情精品久久久久久变态 | 久久久久久亚洲 | 欧美日韩国产一区二区 | 欧美久久久久 |