JNI Java layer object is associated with C + + underlying object, and the way of long pointer passing is abandoned

JNI Java layer objects are associated with C + + underlying objects in a different way than "long pointer passing"

When developing Android JNI, Java classes and C++ classes are often required to correspond with each other. For example, the Java layer has a class MyGLView.java, and the C++ layer has a class called MyGLView.cpp. Therefore, a jni interface called MyGLViewJNI.cpp is required to associate MyGLView.java with MyGLView.cpp, so that MyGLView.java can directly operate the underlying MyGLView.cpp.

There are usually two ways to associate java layers with c + + layer objects:
1. After the c + + object is new, the pointer will be converted to long type and returned to the java object holder. Every time the java object operates the c + + object, it will pass the c + + object pointer it holds (long type in java) to the jni interface, and then it will be forcibly converted to the c + + object.
2. In the jni interface, after the c + + object new comes out, write the object pointer direction to the long variable of the java object, and the jni interface also stores the corresponding jfield ID. every time the java object operates the c + + object, take the c + + object directly from the c + + of the jni interface, which is the next method.

The code and resolution are as follows:

java object:

public class MyGLView {
    //Mapping with gFields.context of jni interface
    private long mNativeContext;
     private static native long init();
    private static native int create(int vWidth, int vHeight);
//java object package name
static const std::string className = "cn/hongda/opengl/opengles/MyGLView";

struct fields_t {
    jfieldID context;

//Save the C + + object pointer and map it to the mnivecontext of the java object above
static struct fields_t gFields;

//The mnivecontext of java object and gFields.context of jni form a mapping relationship. Reading and writing gFields.context in jni is equivalent to reading and writing the mnivecontext of java object directly
static int cn_hongda_opengl_opengles_MyGLView_init(JNIEnv *env, jobject obj)
    jclass clazz = env->FindClass(className.c_str());
    if (clazz == nullptr)
        LOGE("can't find class %s", className.c_str());
        return -1;
    gFields.context = env->GetFieldID(clazz, "mNativeContext", "J");
    if (nullptr == gFields.context)
        LOGE("can't find field mNativeContext.");
        return 0;

//Get c + + object pointer through gFields.context every time
static MyGLView *getMyGLView(JNIEnv *env, jobject obj)
    return (MyGLView *)env->GetLongField(obj, gFields.context);

//Create the underlying C++ MyGLView object
static int cn_hongda_opengl_opengles_MyGLView_create(JNIEnv *env, jobject obj ,jint width, jint height)
    MyGLView * myGLView = new MyGLView();
    MyGLView *oldMyGLView = (MyGLView*) env->GetLongField(obj, gFields.context);
    //If an old object pointer exists, release the object
    if (oldGLMyGLView != nullptr)
        delete oldGLMyGLView;
    myGLView->initGlContext(width, height);
    //Save the newly created C + + object pointer to gFields.context. Because the mnivecontext of the java object has formed a mapping relationship with it, at this time, the mnivecontext has also been assigned
    env->SetLongField(obj, gFields.context, (jlong) myGLView);
    return 0;

The purpose of this method is to write the C + + object pointer back to the java object, and then use a variable corresponding to it in the jni interface. When using the C + + object, directly convert the variable in the jni interface to the C + + object pointer.

Keywords: Java Android

Added by michaelfn on Thu, 02 Apr 2020 08:42:29 +0300