Android JNI development often encountered C/C++ layer access Java layer objects, such as C/C++ layer create a String return, or access the Java layer provided by MediaCodec, etc. At this point we need to create a Java class by calling the constructor of a Java class via JNI.

Call constructor

A constructor is a special class method, but calling a constructor takes the same steps as calling an instance method of a class. You also need to get the jClass and method ID of the corresponding class.

  • For classes, you can find the corresponding Java type by using FindClass.

  • For the constructor, the method ID is obtained by using the GetMethodID method. The difference is that the constructor name is

    and the return type is void.

  • The constructor is called to create the concrete class by passing in the constructor ID obtained by NewObject.

The following character array constructor of String as an example in C/C++ layer object creation.

public String(char value[])
Copy the code

Corresponding C++ code:

extern "C" JNIEXPORT jstring JNICALL Java_com_qingkouwei_demo_InvokeDemo_invokeStringConstructors(JNIEnv *env, jobject instance) { jclass stringClass; jmethodID cid; jcharArray elemArr; jstring result; Jstring temp = env->NewStringUTF("this is char array"); Const jchar *chars = env->GetStringChars(temp, NULL); int len = 10; stringClass = env->FindClass("java/lang/String"); If (stringClass == NULL) {return NULL; String(char value[]) cid = env->GetMethodID(stringClass, "<init>", "([C] V"); If (cid == NULL) {return NULL;// Error tolerance} // String array as argument elemArr = env->NewCharArray(len); If (elemArr == NULL) {return NULL;} env->SetCharArrayRegion(elemArr, 0, len, chars); Result = (jstring) env->NewObject(stringClass, cid, elemArr); env->DeleteLocalRef(elemArr);  env->DeleteLocalRef(stringClass); return result; }Copy the code

We construct the String array and assign it to it. Then we get the jclass of String and the method ID of the constructor. We call the constructor of Sting by passing in the String array with NewObject.

Other classes, whether provided by the Android system or a variety of custom Java classes, can be created through the above process.

Let’s look at another example of calling a constructor of a custom class, again the Animal class, whose constructor takes a String.

NewObject is actually a method that does two things:

  1. Create class objects;
  2. Call the constructor.

Jni provides the AllocObject creation object and the CallNonvirtualVoidMethod constructor to step through the construction of Java objects. Take a simple class we have customized as an example:

/** * create a class */ extern "C" JNIEXPORT jobject JNICALL with AllocObject Java_com_qingkouwei_demo_InvokeDemo_allocObjectConstructor(JNIEnv *env, jobject instance) { jclass fruitClass; jobject result; jmethodID mid; / / get the corresponding Fruit class fruitClass = env - > FindClass (" com/qingkouwei/demo/bean/Fruit "); If (fruitClass == NULL) {return NULL; } // get Fruit constructor id mid = env->GetMethodID(fruitClass, "<init>", "(Ljava/lang/String;) V"); If (mid == NULL) {return NULL; } // constructor argument jstring args = env->NewStringUTF("creat fruit use AllocObject"); // create an uninitialized object result = env->AllocObject(fruitClass); If (result == NULL) {// return NULL; } env->CallNonvirtualVoidMethod(result, fruitClass, mid, args); If (env->ExceptionCheck()) {env->DeleteLocalRef(result); return NULL; } return result; }Copy the code

The separation of object creation and initialization is implemented here, and methods that are not provided for us in Java are provided in the JNI layer.

Call the method of the parent class

We know that one of the peculiarities of Java is polymorphism, that classes can be inherited or inherited, so how do we call the methods of the parent class when creating Java objects in JNI?

We can call the methods of the parent class from a subclass by calling the CallNonvirtualMethod method.

Call CallNonvirtualMethod (); call CallNonvirtualMethod (); call CallNonvirtualMethod ();

  1. For reference types, call CallNonvirtualObjectMethod method;
  2. For the base type, called CallNonvirtualBooleanMethod, CallNonvirtualIntMethod, etc;
  3. For those with no return value type, call the CallNonvirtualVoidMethod method.

We implement a getName method for calling a water ghost in an apple:

/ / extern "C" JNIEXPORT void JNICALL / / extern "C" JNIEXPORT void JNICALL Java_com_qingkouwei_demo_Demo_InvokeDemo_callSuperMethod(JNIEnv *env, jobject instance) { jclass apple_cls; // Apple class type jmethodID apple_cid; // Apple class constructor id jstring apple_name; // Apple class constructor parameter jobject Apple; / / get the corresponding class apple_cls = env - > FindClass (" com/qingkouwei/demo/bean/Apple "); if (apple_cls == NULL) { return; Apple_cid = env->GetMethodID(apple_cls, "<init>", "(Ljava/lang/String;) V"); if (apple_cid == NULL) { return; } // prepare constructor argument apple_name = env->NewStringUTF("this is apple name"); Apple = env->NewObject(apple_cls, apple_cid, apple_name); if (apple == NULL) { return; } // call jclass fruit_cls; // The type of the parent is jmethodID fruit_mid; / / the called method id of the parent / / get the superclass corresponding class fruit_cls = env - > FindClass (" com/qingkouwei/demo/bean/Fruit "); if (fruit_cls == NULL) { return; Fruit_mid = env->GetMethodID(fruit_cls, "getName", "()Ljava/lang/String; ); if (fruit_mid == NULL) { return; } jstring name = (jstring) env->CallNonvirtualObjectMethod(apple, fruit_cls, fruit_mid); if (name == NULL) { return; } //print LOGI("getName method value is %s", env->GetStringUTFChars(name, NULL)); }Copy the code

Apple as a subclass of Fruit, first by NewObject build subclass Apple object, and then obtain the superclass Fruit jclass id and methods, through CallNonvirtualObjectMethod calls the superclass getName method of Fruit.

summary

This article explained how the JNI layer creates Java layer objects in two ways (one by NewObject and one by AllocObject and CallNonvirtualVoidMethod) and how to call the parent class methods of Java layer class objects in the JNI layer. Provides some ideas for using JNI features for complex projects.