Android NDK开发之数组类型的操作

泪湿孤枕 提交于 2019-11-26 17:36:58

Jni 可以通过JNIEnv提供的方法,对传过来的Java数组进行相应的操作。它提供了两种函数:一种是操作Java的简单型数组的,另一种是操作对象类型数组的。

操作Java的简单型数组

因为速度的原因,简单类型的Java数组,会作为指向本地类型的指针暴露给本地代码调用。因此,它们能作为常规的数组存取。这个指针是指向实际的Java数组或者Java数组的拷贝的指针。另外,数组的布置保证匹配本地类型。
在C/C++中,jintArray 不能用下标对其进行直接存取,必须用到JNI中提供的接口函数进行操作。 为了存取Java简单类型的数组,就要要使用GetXXXArrayElements函数(见表),XXX代表了数组的类型。这个函数把Java数组看成参数,返回一个指向对应的本地类型的数组的指针。

函数 Java 数组类型 本地类型
GetBooleanArrayElements jbooleanArray jboolean
GetByteArrayElements jbyteArray jbyte
GetCharArrayElements jcharArray jchar
GetShortArrayElements jshortArray jshort
GetIntArrayElements jintArray jint
GetLongArrayElements jlongArray jlong
GetFloatArrayElements jfloatArray jfloat
GetDoubleArrayElements jdoubleArray jdouble
JNIEXPORT jint JNICALL Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{
    jint *carr;
    carr = (*env)->GetIntArrayElements(env, arr, false);   //获得Java数组arr的引用的指针
    if(carr == NULL) {
        return 0; /* exception occurred */
    }
    jint sum = 0;
    for(int i=0; i<10; i++) {
        sum += carr[i];
    }
    (*env)->ReleaseIntArrayElements(env, arr, carr, 0);
    return sum;
}

操作对象类型数组

在C/C++代码中,int类型的数组对应JNI中的jintArray,而类似字符串数组这种类型的,在Jni里对应的使用 jobjectArray 来声明,下面是存取访问 jobjectArray 的方法简介:

GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index)
array: a reference to the java.lang.Object array from which the element will be accessed.
index: the array index
功能:返回对应索引值的object.返回的是一个数组元素的值。
 
SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value)
array: a reference to an array whose element will be accessed.
index: index of the array element to be accessed.
value: the new value of the array element.
功能:用来设置对应索引元素的值。

Get/SetXXXArrayRegion函数说明

GetIntArrayRegion(array,jsize start,jsize len,*buf)
array:a reference to an array whose elements are to be copied.
start:the starting index of the array elements to be copied.
len: the number of elements to be copied.
buf: the destination buffer.
功能:把jintArray中的元素复制到buffer中。
  
SetIntArrayRegion(array,jsize start,jsize len,*buf)
array:a reference to a primitive array to which the elements to be copied.
start:the starting index in the primitive array.
len:the number of elements to be copied.
buf:the source buffer.
功能:把buf中的元素copy到jintArray中去。

使用SetXXXArrayRegion与GetXXXArrayRegion就是以复制的方式设置与取出Array数组中的某个值。

关于二维数组和String数组

在Jni中,二维数组和String数组都被视为object数组,因为Array和String被视为object。下面例子实现了构造并返回一个二维int数组:

JNIEXPORT jobjectArray JNICALL Java_ObjectArrayTest_initInt2DArray(JNIEnv *env, jclass cls, int size)
{
    jobjectArray result;
    jclass intArrCls = (*env)->FindClass(env, "[I");              //int数组的class
    result = (*env)->NewObjectArray(env, size, intArrCls, NULL);    //二维int数组的实例
 
    for (int i = 0; i < size; i++) {                     //初始化
        jint tmp[256];                                   /* make sure it is large enough! */
        for(int j = 0; j < size; j++) {
            tmp[j] = i + j;
        }
        jintArray iarr = (*env)->NewIntArray(env, size);
        (*env)->SetIntArrayRegion(env, iarr, 0, size, tmp);     //将tmp复制到iarr中
        (*env)->SetObjectArrayElement(env, result, i, iarr);
        (*env)->DeleteLocalRef(env, iarr);
    }
    return result;
}

最后得特别说明一下,当你使用对数组进行访问后,要确保调用相应的ReleaseXXXArrayElements函数,参数是对应Java数组和GetXXXArrayElements返回的指针,如果必要的话,这个释放函数会复制你做的任何变化(这样它们就反射到java数组),然后释放所有相关的资源,避免发生内存泄漏。


本文转自Zhiweiofli's Blog,转载请注明出处,谢谢。


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!