preface

Recently, a friend who wants to advance Android and learn NDK programming asked me that I have seen a lot of video tutorials on the Internet, most of the topics are about JNI method signature, JNI thread binding, JNI calling Java methods and other main content. In the process of practice, I found that if I need to reuse a C or C++ object, I don’t know how to deal with it. It’s just a question of how Java objects hold Native objects.

After listening to this question, I read the NDK video tutorials on the Internet. Indeed, many tutorials do not introduce how Java objects can reuse a Native object. But this is also a key point in the ACTUAL NDK will inevitably encounter. It is quite true that the teacher brings the tao into the door and the practice is in oneself. In this era of information explosion, the distance between you and knowledge is just like a network cable, so how to open up the distance between everyone? Perhaps this time to see who’s self-study ability, or even untaught frontier ability more than a notch.

What do other people do

I don’t know how to do this, but I’m sure the official Android people will do it, and some well-known C or C++ open source projects will do it. Why don’t you just sneak up and see what they do?

One of the most commonly used classes in Android is Bitmap. Let’s take a look at what it does:

public final class Bitmap implements Parcelable { private static final String TAG = "Bitmap"; /** * Indicates that the bitmap was created for an unknown pixel density. * * @see Bitmap#getDensity() * @see Bitmap#setDensity(int) */ public static final int DENSITY_NONE = 0; // Estimated size of the Bitmap native allocation, not including // pixel data. private static final long NATIVE_ALLOCATION_SIZE = 32; // Convenience for JNI Access @unsupportedappusage private final long mNativePtr; // Convenience for JNI Access @unsupportedappusage private final long mNativePtr;Copy the code

If you have not learned C/C++, how can a Java long hold a Native object? This is where the mystery of C/C++ Pointers comes in. This long does not hold an ordinary number, but a memory address of the object’s Native object. Java does not directly store C or C++ objects. It only stores its address. When we need to reuse this Native object, we only need to get the address of the long type and access it through a pointer. It’s that simple…

Give it a try

Show me the code!!

JNIActivity.java

public class JNIActivity extends AppCompatActivity {

    private Teacher teacher;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_j_n_i);

        teacher = new Teacher();
        teacher.initStudent();
        teacher.educationStudent(teacher.mNativePtr);
    }


    @Override
    protected void onDestroy() {
        if(null != teacher){
            teacher.releaseStudent(teacher.mNativePtr);
            teacher = null;
        }
        super.onDestroy();
    }
}
Copy the code

Create a new Java class: teacher.java

public class Teacher { public long mNativePtr = 0; /** * Initialize a student and store the pointer address in mNativePtr */ public native void initStudent(); /** * Public void educationStudent(long studentPtr); /** * Public void educationStudent(long studentPtr); /** * public void releaseStudent(long studentPtr); /** * public void releaseStudent(long studentPtr); }Copy the code

Create a C++ object class:

Student.h

#ifndef GROWING_STUDENT_H
#define GROWING_STUDENT_H


class Student {

public:
    char *name = nullptr;
    int age = 0;

    Student();
    ~Student();

};

#endif //GROWING_STUDENT_H
Copy the code

Student.cpp

#include "Student.h"

Student::Student() {

}

Student::~Student() {

}

Copy the code

native-lib.cpp

extern "C" JNIEXPORT void JNICALL Java_com_flyer_bspatchupdate_jni_Teacher_initStudent(JNIEnv *env, jobject thiz) { Student *student = new Student; student->age = 18; < span style = "margin-top: 0px; margin-bottom: 0px; // JNI set jclass jc = env->GetObjectClass(thiz); jfieldID jf = env->GetFieldID(jc, "mNativePtr", "J"); env->SetLongField(thiz, jf, (jlong)student); } extern "C" JNIEXPORT void JNICALL Java_com_flyer_bspatchupdate_jni_Teacher_educationStudent(JNIEnv *env, jobject thiz, jlong student_ptr) { if (0 ! = student_ptr) { Student *student = (Student*)student_ptr; student->age = student->age + 1; student->name; } } extern "C" JNIEXPORT void JNICALL Java_com_flyer_bspatchupdate_jni_Teacher_releaseStudent(JNIEnv *env, jobject thiz, jlong student_ptr) { if (0 ! = student_ptr) { Student *student = (Student*)student_ptr; delete student; }}Copy the code

Important comments have been written and debugging using LLDB shows that the same object is indeed obtained in the educationStudent and releaseStudent methods of class Teacher.

I wonder if there’s another way

In fact, the so-called Java object to save C or C++ objects is to establish the only correspondence between Java objects and C or C++ objects, convenient in the next JNI entry function can according to the object passed by Java to obtain the original generated C or C++ objects. Now, is there a one-to-one mapping of any of the data structures that we’ve studied? And if so, how? Can I build a wheel without it?

We programmers say don’t waste your time building a wheel, but that’s a prerequisite. The phrase “don’t repeat the wheel” is useful in production, but not in learning. In our actual projects, of course, we recommend using the industry’s mature, universal wheels, which allows us to focus more on our business and make better products.

But how do you know if you’re going to be able to do this, if you’re not going to be able to do this, if you’re not going to be able to do this better, if you’re not going to be able to do this better?

Pay attention to me, progress together, life is more than coding!!

Wechat public account: Ideological Consciousness