“This is the 8th day of my participation in the August More Text Challenge. For details, see: August More Text Challenge.”

Calling Java methods

Calling static methods

Call thinking

In Java, the way we call a method is to first find the corresponding class, then find the corresponding method in that class, and then call the method.

In JNI, the same is true:

  1. We first need to find the corresponding function with the JVM environmentjclassWhich corresponds to a class in Java.
  2. Once we have the corresponding class, we can use the functions in the JVM environment to get the method to calljmethodIDType.
  3. Access to thejmethodIDAfter that, we can call the corresponding function call corresponding method in the JVM environment to make the function call.
  4. After the call is complete, the related resources are released.
The specific process

Suppose we define two methods in MainActivity:

public static void logMessage(String msg){

    Log.d("NDK", msg);
}

public native void callStaticMethod();
Copy the code

Then we generated the following C++ code for the native method:

JNIEXPORT void JNICALL

Java_com_n0texpecterr0r_ndkdemo_MainActivity_callStaticMethod(JNIEnv *env, jobject instance) {
}
Copy the code

We first find the corresponding class using env’s FindClass method:

jclass cls_main = env->FindClass("com/n0texpecterr0r/ndkdemo/MainActivity");
Copy the code

As you can see, the argument needed for FindClass is the full path of the class. The jClass we get is better judged empty

And then we need to get jmethodID for the method that we’re going to call.

jmethodID mth_static_method = env->GetMethodID(cls_main,"logMessage","(Ljava/lang/String;) V");Copy the code

Since logMessage is static, we call env’s GetStaticMethodID method, passing in the jclass method name and the method signature.

We can then call the corresponding method using env->CallXXXXXMethod.

Since our logMessage method is static and returns a void method, we can use the CallStaticVoidMethod

Jstring STR = env->NewStringUTF(" this is the Log called from JNI "); env->CallStaticVoidMethod(cls_main,mth_static_method,str);Copy the code

After the call is complete, we can use env’s DeleteLocalRef method to free the variable we just declared.

env->DeleteLocalRef(cls_main);

env->DeleteLocalRef(str);
Copy the code

Thus, after calling the callStaticMethod method in MainActivity, such a log will be printed

D/NDK: This is the Log of the call from JNI

The complete code is as follows:

JNIEXPORT void JNICALL Java_com_n0texpecterr0r_ndkdemo_MainActivity_callStaticMethod(JNIEnv *env, Jobject instance) {/ / find the corresponding class jclass cls_main = env - > FindClass (" com/n0texpecterr0r ndkdemo/MainActivity "); if(cls_main == NULL) return; MethodId jmethodID mth_static_method = env-> getstaticdid (cls_main,"logMessage","(Ljava/lang/String;)) V"); if(mth_static_method == NULL) return; // Construct the String variable jString STR = env->NewStringUTF(" this is the Log called from JNI "); // Call static method env->CallStaticVoidMethod(cls_main,mth_static_method, STR); Env ->DeleteLocalRef(cls_main); env->DeleteLocalRef(str); }Copy the code

With jClasses in place, we can also modify static variables by getting jfieldID and then calling env’s SetStaticObjectField method. Similar to the previous one.

Call instance method

Suppose we have the following class

public class Adder { private int arg1; private int arg2; public Adder(int arg1, int arg2) { this.arg1 = arg1; this.arg2 = arg2; } public int doAdd(){ return arg1+arg2; }}Copy the code
Call thinking

Calling an instance method is a little more complicated than calling a static method

  1. Find the correspondingjclass
  2. Call its constructor
  3. Create its object
  4. Call its method
The specific process
JNIEXPORT jint JNICALL Java_com_n0texpecterr0r_ndkdemo_MainActivity_addNative(JNIEnv *env, jobject instance, jint arg1, Jint arg2) {/ / find the corresponding class jclass cls_adder = env - > FindClass (" com/n0texpecterr0r ndkdemo/Adder "); JmethodID mth_constructor = env->GetMethodID(cls_adder,"<init>","(II)V"); Jobject adder = env->NewObject(cls_adder, mth_constructor,arg1,arg2); // Obtain the add method jmethodID mth_add = env->GetMethodID(cls_adder,"doAdd","()I"); Jint result = env->CallIntMethod(adder,mth_add); Env ->DeleteLocalRef(cls_adder); env->DeleteLocalRef(adder); // Return result; }Copy the code

As you can see, when you get the id of the constructor, you specify the method name

.

Handling of object references

Why deal with references to objects

When we create an object using new in Java, we can use the object freely without caring when it is reclaimed, because the collection of the object is managed by GC. But what about objects passed to the Native layer using JNI?

After passing the object to the Native language, the Native layer holds the Java object, which can cause a memory leak if we don’t handle it properly. Therefore, when Java objects are used in the Native layer, this reference needs to be freed.

Handling of references

Let’s take a look at the handling of array references

JNIEXPORT void JNICALL Java_com_n0texpecterr0r_ndkdemo_MainActivity_useCppQSort(JNIEnv *env, jobject instance, jintArray jarray) { jint* arrayElemts = env->GetIntArrayElements(jarray, NULL); jsize arraySize = env->GetArrayLength(jarray); . Env ->ReleaseIntArrayElements(jarray, arrayElemts, JNI_COMMIT); }Copy the code

If we pass an array object to C++, a variable in C++ will hold the reference to array. Since both arrays and objects are references in Java, they will open up a space in the heap, but we need to free the reference when we are done with the object, otherwise it will cause a memory leak. The last argument to an array element can be passed two values:

  • JNI_ABORT, Java arrays are not updated, but C/C++ arrays are freed
  • JNI_COMMIT, Java array is updated, C/C++ array is not freed (after function execution, array is still freed)

In fact, all Java objects need to be freed in the Native layer (including object references created in the Native layer).

Reference classification

In Java there are strong and weak references, and in C/C++ there are also global references, local references, weak global references, and so on.

Local reference

Local references refer to Java objects used or created by C/C++ and need to be told to reclaim them when appropriate. (Manually release the object via DeleteLocalRef)

JNIEXPORT void JNICALL 

Java_com_n0texpecterr0r_ndkdemo_MainActivity_localRef(JNIEnv *env, jobject instance) {

    // 找到类

    jclass dateClass = env->FindClass("java/util/Date");

    // 得到构造方法ID

    jmethodID dateConstructorId = env->GetMethodID(dateClass, "<init>", "()V");

    // 创建Date对象

    jobject dateObject = env->NewObject(dateClass, dateConstructorId);

    // 创建一个局部引用

    jobject dateLocalRef = env->NewLocalRef(dateObject);

    ...

    // 不再使用对象,通知GC回收对象

    env->DeleteLocalRef(dateLocalRef);

    // 因为dateObject也是局部对象,可以直接回收dateObject对象

    // env->DeleteLocalRef(dateObject);

}
Copy the code
Global references

Global references are shared (they can span multiple threads), and memory usage is controlled manually

jstring globalStr; Void JNICALL Java_com_n0texpecterr0r_ndkdemo_MainActivity_createGlobalRef(JNIEnv *env, jobject jobj) { jstring jStr = env->NewStringUTF("N0tExpectErr0r"); // Create a global reference globalStr = env->NewGlobalRef(jStr); } /* Use global references */ JNIEXPORT jString JNICALL Java_com_n0texpecterr0r_ndkdemo_MainActivity_useGlobalRef(JNIEnv *env, jobject jobj) { return globalStr; } /* Release global references */ JNIEXPORT void JNICALL Java_com_n0texpecterr0r_ndkdemo_MainActivity_deleteGlobalRef(JNIEnv *env, Jobject jobj) {// Release global reference env->DeleteGlobalRef(globalStr); }Copy the code

Weak global references save memory. They can be used to refer to an object that is not commonly used. If NULL, they can be created temporarily.

Create: NewWeakGlobalRef

Destruction: DeleteWeakGlobalRef

It’s not over yet. I feel a little flustered at work. I’ll talk about it tomorrow.

Public account: Programmer Meow (focus on Android study notes, interview questions and IT information sharing)