深入浅出Android NDK之JNI数组操作

目录
上一篇 深入浅出Android NDK之JNI字符串转换

在学习本章内容之前,建议你先学习上一章的内容。
深入浅出Android NDK之JNI字符串转换
因为有很多相似概念,所以本章不会重新讲解。

和字符串一样,jni对数组类型也提供了特殊支持。提供了9种数组:
jbooleanArray,jbyteArray,jcharArray,jshortArray,jintArray,jlongArray,jfloatArray,jdoubleArray,jobjectArray
分别对应java中的:
boolean[],byte[],char[],short[],int[],long[],float[],double[],Object[]。
jobjectArray可以对应java中的一切类对像数组,比如,String[],Integer[],InputStream[],File[]等等。

对于数组JNIEnv中共提供了以下API进行支持:

jsize GetArrayLength(jarray array);

jobjectArray NewObjectArray(jsize length, jclass elementClass,jobject initialElement);
jobject GetObjectArrayElement(jobjectArray array, jsize index);
void SetObjectArrayElement(jobjectArray array, jsize index, jobject value);

jbooleanArray NewBooleanArray(jsize length);
jboolean* GetBooleanArrayElements(jbooleanArray array, jboolean* isCopy);
void ReleaseBooleanArrayElements(jbooleanArray array, jboolean* elems, jint mode);
void GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, jboolean* buf);
void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, const jboolean* buf);   
	
jbyteArray NewByteArray(jsize length);
jbyte* GetByteArrayElements(jbyteArray array, jboolean* isCopy);
void ReleaseByteArrayElements(jbyteArray array, jbyte* elems, jint mode);
void GetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte* buf);
void SetByteArrayRegion(jbyteArray array, jsize start, jsize len, const jbyte* buf); 
	   
jcharArray NewCharArray(jsize length);
jchar* GetCharArrayElements(jcharArray array, jboolean* isCopy);
void ReleaseCharArrayElements(jcharArray array, jchar* elems, jint mode);
void GetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar* buf);
void SetCharArrayRegion(jcharArray array, jsize start, jsize len, const jchar* buf); 
	  
jshortArray NewShortArray(jsize length);
jshort* GetShortArrayElements(jshortArray array, jboolean* isCopy);
void ReleaseShortArrayElements(jshortArray array, jshort* elems, jint mode);
void GetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort* buf);
void SetShortArrayRegion(jshortArray array, jsize start, jsize len, const jshort* buf); 
	  
jintArray NewIntArray(jsize length);
jint* GetIntArrayElements(jintArray array, jboolean* isCopy);
void ReleaseIntArrayElements(jintArray array, jint* elems, jint mode);
void GetIntArrayRegion(jintArray array, jsize start, jsize len, jint* buf);
void SetIntArrayRegion(jintArray array, jsize start, jsize len, const jint* buf); 
		   
jlongArray NewLongArray(jsize length);
jlong* GetLongArrayElements(jlongArray array, jboolean* isCopy);
void ReleaseLongArrayElements(jlongArray array, jlong* elems, jint mode);
void GetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong* buf);
void SetLongArrayRegion(jlongArray array, jsize start, jsize len, const jlong* buf);    
	   
jfloatArray NewFloatArray(jsize length);
jfloat* GetFloatArrayElements(jfloatArray array, jboolean* isCopy);
void ReleaseFloatArrayElements(jfloatArray array, jfloat* elems, jint mode);
void GetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat* buf);   
void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, const jfloat* buf); 
	   
jdoubleArray NewDoubleArray(jsize length);
jdouble* GetDoubleArrayElements(jdoubleArray array, jboolean* isCopy);
void ReleaseDoubleArrayElements(jdoubleArray array, jdouble* elems, jint mode);
void GetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble* buf);
void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, const jdouble* buf);

void* GetPrimitiveArrayCritical(jarray array, jboolean* isCopy);
void ReleasePrimitiveArrayCritical(jarray array, void* carray, jint mode);

我们可以看到对于基本类型的数组提供的函数基本都是一样的,以jintArray为例:

jintArray NewIntArray(jsize length);
jint* GetIntArrayElements(jintArray array, jboolean* isCopy);
void ReleaseIntArrayElements(jintArray array, jint* elems, jint mode);
void GetIntArrayRegion(jintArray array, jsize start, jsize len, jint* buf);
void SetIntArrayRegion(jintArray array, jsize start, jsize len, const jint* buf); 
void* GetPrimitiveArrayCritical(jarray array, jboolean* isCopy);
void ReleasePrimitiveArrayCritical(jarray array, void* carray, jint mode);

和上一章操作String的API进行比较:

jstring NewString(const jchar* unicodeChars, jsize len);
const jchar* GetStringChars(jstring string, jboolean* isCopy);
void ReleaseStringChars(jstring string, const jchar* chars);
void GetStringRegion(jstring str, jsize start, jsize len, jchar* buf);
const jchar* GetStringCritical(jstring string, jboolean* isCopy);
void ReleaseStringCritical(jstring string, const jchar* carray);

也大同小异,只是多了修改数组的操作:

void SetIntArrayRegion(jintArray array, jsize start, jsize len, const jint* buf); 

对于String的Get系统函数返回值是const jchar*,而对于jintArray的Get系统函数返回值是jint*,区别在const,因为字符串是不可变的,所以返回值是const。
对于数组的Get系列,isCopy参数的意义和Strinng的是一样的。
对于Release系列函数和String相比,多了一个jint mode的参数。
我们知道我们调用Get系列函数时,得于的C语言的数组指针有可能是一个拷贝,也有就是原始的引用。如果是原始引用,那mode参数基本上没什么作用了,传什么值 过去都可以。
在是拷贝的情况下,假设有以下代码:

jboolean isCopy;
jint *elem = env->GetIntArrayElements(javaArray,&isCopy);

假设isCopy的返回值是true,也就是elem是一份拷贝。
如果我们得到elem的值后,我们修改了elem的值,这个时候mode参数我们入当传入0。
0的意思是,将elem拷贝到原始数组中去,并且释放elem。

elem[0] = 1;
env->ReleaseIntArrayElements(javaArray, elem, 0);

如果我们得到elem的值后,我们并不修改,仅仅只用来读取。这种情况下我们应当传入JNI_ABORT。JNI_ABORT会释放elem,但并不会将elem的内容拷贝到原始数组,因为我们并没有修改,所以就没必要再次拷贝了。

env->ReleaseIntArrayElements(javaArray, elem, JNI_ABORT);

mode还有可以指定为JNI_COMMIT,JNI_COMMIT的意思是将elem的内容拷贝到原始数组,但是并不释放elem,所以你可以继续修改或者读取elem,等完事后,再次调用ReleaseIntArrayElements传入0或者JNI_ABORT来释放elem。不管怎么样,elem最终是一定要释放的。这种情况太少见了,所以我建议你忘掉JNI_COMMIT。我实在是想像不出应用场景。

下面我们来总结一下:
如果修改了数组内容,那么mode传0。
如果只读,那么mode传JNI_ABORT。

对于jobjectArray,并没有提供批量操作函数(GetObjectArrayElements,GetObjectRegion,SetObjectArrayRegion),所以我们只能用以下API,老老实实的一个一个读取赋值:

jobject GetObjectArrayElement(jobjectArray array, jsize index);
void SetObjectArrayElement(jobjectArray array, jsize index, jobject value);

下一篇 深入浅出Android NDK之jni对象操作

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值