Android JNI and NDK learning (5): JNI call array

Overview

Today we continue to study the JNI array, this article is only as a note, in case you forget it in the future

Array

JNI divides java types into two types, basic data types and reference data types. Reference data types are uniformly represented by jobject, and arrays are also divided into basic data types and reference data types. Reference data types are represented by jobjectarray.

Array of basic data types

Let's first analyze the APIs related to arrays of basic data types

Get< PrimitiveType >ArrayElements

Returns an array of basic data types, which PrimitiveTyperefers to the basic data types. For example, if you want to get an array of int data type, then it PrimitiveTypeis int

NativeType *Get<PrimitiveType>ArrayElements(JNIEnv *env,
                        ArrayType array, jboolean *isCopy);

  • ArrayType array: represents the java array object
  • jboolean *isCopy: *isCopywhen JNI_TRUE, the pointer points to the copy of the original array, *isCopwhen it is JNI_FALSE, the pointer points to the original array

If the function pointer points to the original array, all modifications are made on the original array. If the function pointer points to the copy array, then all modifications are made on the copy array, and the element group is not affected.

We, you need to ensure that when the copy occurs, the modified data can be synchronized to the original array, Release<PrimitiveType>ArrayElementsthis is the role

Release< PrimitiveType >ArrayElements

void Release<PrimitiveType>ArrayElements(JNIEnv *env,
                ArrayType array, NativeType *elems, jint mode);
  • ArrayType array: the original array java object
  • NativeType *elems: pointer of JNI array type, local array
  • jint mode: Means 0to synchronize the modification to the original array and release the local array
    JNI_COMMIT: Synchronize the modification to the original array, but do not release the local array
    JNI_ABORT: Do not synchronize the modification to the original array, but release the local array

When the Get<PrimitiveType>ArrayElements function does not copy, the mode has no effect

Actual combat

java code

public class TextJniArray {
    
    

    static {
    
    
        System.loadLibrary("textjniarray");
    }


    public native void textArray(int[] array);


}

C code

#include <jni.h>
#include <android/log.h>

static void native_text_array(JNIEnv *env, jobject jobject1, jintArray array) {
    
    

    //获取数组长度
    jsize length = env->GetArrayLength(array);
    //获取本地数组
    jint *native_intaray = env->GetIntArrayElements(array, NULL);
    //操作本地数组
    for(int i=0;i<length;i++){
    
    
        native_intaray[i]+=100;
    }
    //释放本地数组
    env->ReleaseIntArrayElements(array,native_intaray,0);
}


static const JNINativeMethod nativeMethod[] = {
    
    
        {
    
    "textArray", "([I)V", (void *) native_text_array}
};

static int registNativeMethod(JNIEnv *env) {
    
    
    int result = -1;

    jclass class_text = env->FindClass("com.taobao.alinnkit.ndk1.TextJniArray");
    if (env->RegisterNatives(class_text, nativeMethod,
                             sizeof(nativeMethod) / sizeof(nativeMethod[0])) == JNI_OK) {
    
    
        result = 0;
    }
    return result;
}

jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    
    
    JNIEnv *env = NULL;
    int result = -1;

    if (vm->GetEnv((void **) &env, JNI_VERSION_1_1) == JNI_OK) {
    
    
        if (registNativeMethod(env) == JNI_OK) {
    
    
            result = JNI_VERSION_1_6;
        }
        return result;
    }
}

transfer

  @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        int[] a = {
    
    0, 1, 2, 3, 4, 5};
        for (int i = 0; i < 6; i++) {
    
    
            Log.d("mmm调用前数组数据", a[i] + "/");
        }
        new TextJniArray().textArray(a);

        for (int i = 0; i < 6; i++) {
    
    
            Log.d("mmm调用后数组数据", a[i] + "/");
        }
    }

print

D/mmm调用前数组数据: 0/
D/mmm调用前数组数据: 1/
D/mmm调用前数组数据: 2/
D/mmm调用前数组数据: 3/
D/mmm调用前数组数据: 4/
D/mmm调用前数组数据: 5/

D/mmm调用后数组数据: 100/
D/mmm调用后数组数据: 101/
D/mmm调用后数组数据: 102/
D/mmm调用后数组数据: 103/
D/mmm调用后数组数据: 104/
D/mmm调用后数组数据: 105/

Get< PrimitiveType >ArrayRegion

void Get<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array,
                                jsize start, jsize len, NativeType *buf);

  • ArrayType array: java array object
  • jsize start: copy start position
  • jsize len: the length of the copy
  • NativeType *buf: local buffer array

The function of this function is to copy the java array ArrayType arrayto the local array NativeType *buf. If you modify the local array and need to be synchronized to the java array, you need to callSet<PrimitiveType>ArrayRegion

Set< PrimitiveType >ArrayRegion

void Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array,
            jsize start, jsize len, const NativeType *buf);
  • ArrayType array: java primitive array
  • jsize start: start index
  • jsize len: copy length
  • const NativeType *buf: local buffer array

The function of this function is to NativeType *bufwrite the local array data back to the original java array. The starting point is start and the length is len.

Actual combat

Only C code is posted this time

static void native_text_array1(JNIEnv *env, jobject jobject1, jintArray array) {
    
    

    //获取数组长度
    jsize length = env->GetArrayLength(array);
    //创建本地缓存数组
    jint native_array[length - 2];
    //进行数组考别
    env->GetIntArrayRegion(array, 2, length - 2, native_array);

    for (int i = 0; i < length - 2; ++i) {
    
    
        native_array[i] += 100;
    }
    //把修改数据写回原数组
    env->SetIntArrayRegion(array, 2, length - 2, native_array);

}

print

D/mmm调用前数组数据: 0/
D/mmm调用前数组数据: 1/
D/mmm调用前数组数据: 2/
D/mmm调用前数组数据: 3/
D/mmm调用前数组数据: 4/
D/mmm调用前数组数据: 5/

D/mmm调用后数组数据: 0/
D/mmm调用后数组数据: 1/
D/mmm调用后数组数据: 102/
D/mmm调用后数组数据: 103/
D/mmm调用后数组数据: 104/
D/mmm调用后数组数据: 105/

New< PrimitiveType >Array

This method can create an array in the JNI layer, and then return to java

Actual combat

C code

static jintArray native_text_array2(JNIEnv *env, jobject jobject1) {
    
    
    jintArray array = env->NewIntArray(2);

    jint *native_array = env->GetIntArrayElements(array, NULL);

    for (int i = 0; i < 2; ++i) {
    
    
        native_array[i] = 100 + i;
    }

    env->ReleaseIntArrayElements(array, native_array, 0);

    return array;
}

transfer

 int[] a = new TextJniArray().textArray2();

        for (int i = 0; i < 2; i++) {
    
    
            Log.d("mmm数组数据", a[i] + "/");
        }

print

D/mmm数组数据: 100/
D/mmm数组数据: 101/

Reference data type array

Let's take a look at the API that needs to be used

GetObjectArrayElement

jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index);

Gets an array of arrayindex indexelements under

IsInstanceOf

jboolean IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz);

Used to determine whether the object obj is an instance object of the class class

Actual combat

Ready to reference data types

public class Person {
    
    
    public String name;

    public Person(String name) {
    
    
        this.name = name;
    }

    public void say() {
    
    
        Log.d("mmm", name + "在说话");
    }
}

Prepare native methods

public native void textArray3(Person[] persons);

Prepare for C implementation

static void native_text_array3(JNIEnv *env, jobject jobject1, jobjectArray jobjectArray1) {
    
    

    //获取数组长度
    jsize length = env->GetArrayLength(jobjectArray1);
    //获取person的class对象
    jclass jclass_person = env->FindClass("com.taobao.alinnkit.ndk1.Person");

    if (jclass_person == NULL) {
    
    
        return;
    }
    //获取方法
    jmethodID jmethodId_say = env->GetMethodID(jclass_person, "say", "()V");

    if (jmethodId_say == NULL) {
    
    
        return;
    }

    for (int i = 0; i < length; ++i) {
    
    
        //获取java引用数组中的元素
        jobject jobject2 = env->GetObjectArrayElement(jobjectArray1, i);
        //判断元素的类型
        if (env->IsInstanceOf(jobject2, jclass_person)) {
    
    
            //调用元素的方法
            env->CallVoidMethod(jobject2, jmethodId_say);
        }
    }

}

transfer

        Person[] people = new Person[2];
        people[0] = new Person("jj");
        people[1] = new Person("oj");
        new TextJniArray().textArray3(people);

Print data

D/mmm: jj在说话
D/mmm: oj在说话

NewObjectArray

jobjectArray NewObjectArray(JNIEnv *env, jsize length,
                        jclass elementClass, jobject initialElement);

The function is NewObjectArrayto elementClasscreate an lengtharray of reference data types in the JNI layer, the function will create a length of reference data type array according to the type

If the fourth parameter is specified, the array will be initialized. If NULL is specified, all elements of the array are null

SetObjectArrayElement

void SetObjectArrayElement(JNIEnv *env, jobjectArray array, 
                        jsize index, jobject value);

Is an array, set the value under the index index to value

NewObject & NewObjectA & NewObjectV

jobject NewObject(JNIEnv *env, jclass clazz,
                jmethodID methodID, ...);

jobject NewObjectA(JNIEnv *env, jclass clazz,
                jmethodID methodID, const jvalue *args);

jobject NewObjectV(JNIEnv *env, jclass clazz,
                jmethodID methodID, va_list args);

The difference between these three parameters is that the incoming parameters are not the same, but the effect is the same

  • Parameters class representatives, java class object, you can FindClassbe looking for
  • The parameter methodID refers to the java constructor, which can GetMethodIDbe obtained by using the parameter name passed in <init>, and the return value of the parameter name is V

AllocObject

jobject AllocObject(JNIEnv *env, jclass clazz);

This function will allocate memory for objects of the clazz class, without calling the constructor of the class class, and return a reference to this object

Actual combat

Prepare the native method of java

public native Person[] textArray4(int length);

Prepare for C implementation

static jobjectArray native_text_array4(JNIEnv *env, jobject jobject1, jint length) {
    
    

    jclass jclass_person = env->FindClass("com.taobao.alinnkit.ndk1.Person");

    if (jclass_person == NULL) {
    
    
        return NULL;
    }

    //获取person的构造方法
    jmethodID jmethodId_gouzao = env->GetMethodID(jclass_person, "<init>", "(Ljava/lang/String;)V");

    if (jmethodId_gouzao == NULL) {
    
    
        return NULL;
    }

    //创建引用数组
    jobjectArray array_person = env->NewObjectArray(length, jclass_person, NULL);

    for (int i = 0; i < length; ++i) {
    
    
        jobject person = NULL;
        if (i == 0) {
    
    
            //构造方法创建对象
            person = env->NewObject(jclass_person, jmethodId_gouzao, env->NewStringUTF("小红"));
        }

        if (i == 1) {
    
    
            person = env->AllocObject(jclass_person);
            //直接分配内存
            jmethodID setname = env->GetMethodID(jclass_person, "setName", "(Ljava/lang/String;)V");
            env->CallVoidMethod(person, setname, env->NewStringUTF("小明"));
        }

        //把初始化好的对象赋值给数组
        env->SetObjectArrayElement(array_person, i, person);
        //释放局部变量
        env->DeleteLocalRef(person);
    }

    return array_person;

}

transfer

  Person[] people1 = new TextJniArray().textArray4(2);

        for (int i = 0; i < people1.length; i++) {
    
    
            people1[i].say();
        }

Print data

 D/mmm: 小红在说话
 D/mmm: 小明在说话

reference

https://juejin.im/post/5d2ed0ac6fb9a07f0655a267

Guess you like

Origin blog.csdn.net/qq_34760508/article/details/106619804