Introduction to JNI & NDK in Android (2) Java and Native call each other

We have demonstrated in the last article "Introduction to JNI & NDK in Android (Part 1) NDK and JNI" through Demo, how to call C ++ code in Java code Method. First of all, the process of calling Java methods in JNI is to find the class by class name, then find the method id according to the method name, and finally you can call this method. If you call a non-static method in Java, you need to construct an object of the class before calling it. In fact, the implementation is very similar to our usual use of reflection in Java. Let's take a look at the reverse call of the Java method in JNI by extending the Demo in the previous article.

1 Expand Hello world

Modify JNIUtils.java to add a static method for inverse call in JNI:

public class JNIUtils {
    static {
        System.loadLibrary("jni-demo");
    }
    public static native String getInfo();
    public static String getJavaInfo(String info, int index) {
        return info + index;
    }
}

Modify JNIUtils.cpp :

#include "com_zyx_jnidemo_JNIUtils.h"
#include <stdio.h>
#include <android/log.h>

JNIEXPORT jstring JNICALL Java_com_zyx_jnidemo_JNIUtils_getInfo(JNIEnv * env, jclass thiz) {
    __android_log_print(ANDROID_LOG_DEBUG, "zyx", "Hello world from JNI !");
    //return env->NewStringUTF("Hello world from JNI !");
    jclass clazz = env->FindClass("com/zyx/jnidemo/JNIUtils");
    if (clazz == NULL) {
        return env->NewStringUTF("find class error");
    }
    jmethodID methodId = env->GetStaticMethodID(clazz, "getJavaInfo", "(Ljava/lang/String;I)Ljava/lang/String;");
    if(methodId == NULL) {
        return env->NewStringUTF("find method error");
    }
    jstring info = env->NewStringUTF("Hello world from JNI !");
    jint index = 2;
    return (jstring)env->CallStaticObjectMethod(clazz, methodId, info, index);
}

Very simple modification, and then re-compile the program, running visible:

 

2 Native code reverse call Java layer code

As you can see from the modified code above, the Java_com_zyx_jnidemo_JNIUtils_getInfo function first passes the class name through the FindClass function: com / zyx / jnidemo / JNIUtils to find the class, and then uses the GetStaticMethodID function to pass in the class variables, method name and method signature to find Method, and then pass the class, method and two corresponding parameters through the CallStaticObjectMethod function of the JNIEnv object to complete the final call process. This completes the process of calling JNI from Java and then calling Java methods from JNI. Among them, the functions of FindClass, GetStaticMethodID and CallStaticObjectMethod are all defined in jni.h, let's take a look at the use of these functions in detail:

2.1 Get Class object

jclass FindClass(const char* clsName)

Get jclass by the name of the class (package name, but with "/" instead of "". "). For example, the above code: jclass clazz = env-> FindClass ("com / zyx / jnidemo / JNIUtils");

jclass GetObjectClass(jobject obj)

Obtain jclass by object instance, equivalent to getClass () function in Java

jclass getSuperClass(jclass obj)

Through jclass you can get the jclass object of its parent class

2.2 Get attribute method

jfieldID GetFieldID(jclass clazz, const char* name, const char* sig)

Get an attribute

jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)

Get a method

jfieldID GetStaticFieldID(jclass clazz, const char* name, const char* sig)

Get a static property

jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig)

Get a static method. For example, the above code: jmethodID methodId = env-> GetStaticMethodID (clazz, "getJavaInfo", "(Ljava / lang / String; I) Ljava / lang / String;");

2.3 Construct an object

jobject NewObject(jclass clazz, jmethodID methodID, ...)

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

jobject NewObjectV(jclass clazz, jmethodIDmethodID,va_list args)

Construct an object, such as:

jmethodID methodId = env-> GetMethodID (clazz, "method name", "method signature");

jobject obj = env->NewObject(clazz, methodId);

2.4 Call method

jobject (*CallStaticXXXMethod)(JNIEnv*, jclass, jmethodID, ...);

Call a static method and return XXX, such as the above code: (jstring) env-> CallStaticObjectMethod (clazz, methodId, info, index);

jobject (*CallXXXMethod)(JNIEnv*, jobject, jmethodID, ...);

Call an object static method and return XXX

3 Method signature

The third parameter mentioned in the extension Demo mentioned above using the GetStaticMethodID function is the method signature: (Ljava / lang / String; I) Ljava / lang / String;, so what exactly is this method signature? How did you get it? Let's talk about how the method signature is.

Because Java supports method overloading, that is, the same method name can have different parameters or return types. Then if JNI is just based on the method name, there is no way to find the overloaded method, so to solve this problem, JNI derived a concept of signature, that is, the combination of parameter type and return value type, if you have a function The signature information and the function name of this function, we can find the corresponding function in the Java layer.

2.1 Use the command to view the method signature

In the command line, you can view the signature of the method in the entire class by using the command: javap -s xxx.class, as shown in the figure:

The red box is the value to be passed in the demo above.

2.2 Inference method signature

JNI data types include two types: basic types and reference types. The type signature is to identify a specific Java type.

The basic types are mainly jboolean, jchar, jint, etc. Most of them correspond to the data types in Java, but there is an additional j in front, and the signature is mostly capitalized, except for special, as shown in the following table:

JNI type

Java type

Type signature

jboolean

boolean

Z (because B is used by byte)

jbyte

byte

B

jchar

char

C

jshort

short

S

be

int

I

jlong

long

J (because L represents the signature of the class)

jfloat

float

F

jdouble

double

D

void

void

V

Reference types mainly include classes, objects, and arrays. The signature of a class is relatively simple. It takes the form of "L + package name + class name +;" (especially pay attention to the semicolon not to be omitted), just need to replace .. Yes, and the data type array is "[+ data type signature", if it is a multi-dimensional array, its signature is n [+ type signatures, the corresponding relationship is as follows:

JNI type

Java type

Type signature

jobject

Object

Ljava / lang / Object;

jclass

Class

Ljava/lang/Class;

jstring

String

Ljava/lang/String;

jobjectArray

Object[]

[Ljava / lang / Object;

jbooleanArray

boolean[]

[FROM

jbyteArray

byte[]

[B

jcharArray

char[]

[C

jshortArray

short[]

[S

jintArray

int[]

[I

jlongArray

long[]

[J

jfloatArray

float[]

[F

jdoubleArray

double[]

[D

jthrowable

Throwable

Ljava/lang/Throwable

A method's signature is "(parameter type signature) + return value type signature", like the method above: String getJavaInfo (String info, int index), so its signature should be: (Ljava / lang / String; I ) Ljava / lang / String;, be careful not to miss the semicolon.

 

 

Click to download example

 

 

 

Published 106 original articles · praised 37 · 80,000 views

Guess you like

Origin blog.csdn.net/lyz_zyx/article/details/88669205