An overview of the

Today we’ll continue learning about JNI arrays, but this article is just a note in case you forget it later

An array of

JNI divides Java types into two classes: basic data types and reference data types. Reference data types are represented by Jobject, and arrays are also classified into basic data types and reference data types. The reference data type is represented by Jobjectarray

An array of primitive data types

Let’s start by examining the array-related apis for the basic data types

Get< PrimitiveType >ArrayElements

Returns an array of primitive data types, and PrimitiveType is the primitive data type, so for example, if you’re getting an array of data types of int, then PrimitiveType is int

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

Copy the code
  • ArrayType Array: Represents a Java array object
  • Jboolean * isCopy:*isCopyWhen JNI_TRUE, the pointer points to a 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 changes are made on the original array. If the function pointer points to a copy array, all changes are made on the copy array, and the group of elements is not affected

You need to make sure that when copying happens, the modified data can be synchronized to the original array, and Release ArrayElements does that

Release< PrimitiveType >ArrayElements

void Release<PrimitiveType>ArrayElements(JNIEnv *env,
                ArrayType array, NativeType *elems, jint mode);
Copy the code
  • ArrayType Array: specifies the original array of Java objects
  • NativeType *elems: Pointer to JNI array type, local array
  • Jint mode:0Synchronizes changes to the original array and frees the local arrayJNI_COMMIT: synchronizes changes to the original array, but does not free the local arrayJNI_ABORT: does not synchronize changes to the original array, but frees the local array

When the Get< PrimitiveType >ArrayElements function is not copied, mode has no effect

In actual combat

Java code

public class TextJniArray {

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


    public native void textArray(int[] array);


}
Copy the code

C code

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

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

    // Get the array length
    jsize length = env->GetArrayLength(array);
    // Get the local array
    jint *native_intaray = env->GetIntArrayElements(array.NULL);
    // Operate on local arrays
    for(int i=0; i<length; i++){ native_intaray[i]+=100;
    }
    // Free the local array
    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.text.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;
        }
        returnresult; }}Copy the code

call

  @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("Array data before MMM call", a[i] + "/");
        }
        new TextJniArray().textArray(a);

        for (int i = 0; i < 6; i++) {
            Log.d("Array data after MMM call", a[i] + "/"); }}Copy the code

print

D/ MMM array data before calling:0/ D/ MMM1/ D/ MMM2/ D/ MMM3/ D/ MMM4/ D/ MMM5/ D/ MMM100/ D/ MMM101/ D/ MMM102/ D/ MMM103/ D/ MMM104/ D/ MMM105/
Copy the code

Get< PrimitiveType >ArrayRegion

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

Copy the code
  • ArrayType Array: Java array objects
  • Jsize start: indicates the start position of the copy
  • Jsize len: indicates the copy length
  • NativeType *buf: locally cached array

This function copies the Java ArrayType array to the local array NativeType *buf. If you modify the local array and need to synchronize it to the Java array, you need to call Set ArrayRegion

Set< PrimitiveType >ArrayRegion

void Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array,
            jsize start, jsize len, const NativeType *buf);
Copy the code
  • ArrayType Array: Java primitive array
  • Jsize start: starts the index
  • Jsize len: indicates the copy length
  • Const NativeType *buf: local cache array

This function writes the local array NativeType *buf data back to the Java array starting at len

In actual combat

I’ll just post C code this time

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

    // Get the array length
    jsize length = env->GetArrayLength(array);
    // Create a local cache array
    jint native_array[length - 2];
    // Perform array tests
    env->GetIntArrayRegion(array.2, length - 2, native_array);

    for (int i = 0; i < length - 2; ++i) {
        native_array[i] += 100;
    }
    // Write the modified data back to the original array
    env->SetIntArrayRegion(array.2, length - 2, native_array);

}
Copy the code

print

D/ MMM array data before calling:0/ D/ MMM1/ D/ MMM2/ D/ MMM3/ D/ MMM4/ D/ MMM5/ D/ MMM0/ D/ MMM1/ D/ MMM102/ D/ MMM103/ D/ MMM104/ D/ MMM105/
Copy the code

New< PrimitiveType >Array

This method creates arrays at the JNI layer and returns them to Java

In 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;
}
Copy the code

call

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

        for (int i = 0; i < 2; i++) {
            Log.d("MMM array data", a[i] + "/");
        }
Copy the code

print

D/ MMM array data:100/ D/ MMM101/
Copy the code

An array that references a data type

Let’s look at the API we need to use

GetObjectArrayElement

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

Gets the element of array under index index

IsInstanceOf

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

Object obj is an instance of class

In actual combat

Prepare the reference data type

public class Person {
    public String name;

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

    public void say(a) {
        Log.d("mmm", name + "Talking"); }}Copy the code

Prepare native methods

public native void textArray3(Person[] persons);
Copy the code

Preparation C implementation

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

    // Get the array length
    jsize length = env->GetArrayLength(jobjectArray1);
    // Get the class object of person
    jclass jclass_person = env->FindClass("com.text.ndk1.Person");

    if (jclass_person == NULL) {
        return;
    }
    // Get method
    jmethodID jmethodId_say = env->GetMethodID(jclass_person, "say"."()V");

    if (jmethodId_say == NULL) {
        return;
    }

    for (int i = 0; i < length; ++i) {
        // Get the elements in the Java reference array
        jobject jobject2 = env->GetObjectArrayElement(jobjectArray1, i);
        // Determine the type of the element
        if (env->IsInstanceOf(jobject2, jclass_person)) {
            // Call the method of the elementenv->CallVoidMethod(jobject2, jmethodId_say); }}}Copy the code

call

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

Print data

D/ MMM: JJ is talking D/ MMM: OJ is talkingCopy the code

NewObjectArray

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

Copy the code

The NewObjectArray function creates an array of reference microdata types at the JNI layer. The NewObjectArray function creates a length array of reference microdata types based on the elementClass type

If the fourth argument is specified, the array is initialized; if NULL, all elements of the array are NULL

SetObjectArrayElement

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

Copy the code

For array array, set the value under 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);

Copy the code

The difference between these three parameters is that the parameters passed in are different, but the function is the same

  • The class argument represents a Java class object that can passFindClassTo find the
  • The argument methodID refers to the Java constructor, which passesGetMethodIDTo get the name of the parameter passed<init>, the return value of the parameter name is V

AllocObject

jobject AllocObject(JNIEnv *env, jclass clazz);
Copy the code

This function allocates memory for an object of class Clazz without calling the constructor of class and returns a reference to the object

In actual combat

Prepare native methods for Java

public native Person[] textArray4(int length);
Copy the code

Preparation C implementation

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

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

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

    // Get the constructor for person
    jmethodID jmethodId_gouzao = env->GetMethodID(jclass_person, "<init>"."(Ljava/lang/String;) V");

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

    // Create an array of references
    jobjectArray array_person = env->NewObjectArray(length, jclass_person, NULL);

    for (int i = 0; i < length; ++i) {
        jobject person = NULL;
        if (i == 0) {
            // The constructor creates the object
            person = env->NewObject(jclass_person, jmethodId_gouzao, env->NewStringUTF("Little red"));
        }

        if (i == 1) {
            person = env->AllocObject(jclass_person);
            // Allocate memory directly
            jmethodID setname = env->GetMethodID(jclass_person, "setName"."(Ljava/lang/String;) V");
            env->CallVoidMethod(person, setname, env->NewStringUTF("Xiao Ming"));
        }

        // Assign the initialized object to the array
        env->SetObjectArrayElement(array_person, i, person);
        // Release local variables
        env->DeleteLocalRef(person);
    }

    return array_person;

}
Copy the code

call

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

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

Print data

D/ MMM: Xiao Hong is talking D/ MMM: Xiao Ming is talkingCopy the code

reference

Juejin. Cn/post / 684490…