3-ndk学习之jni基础篇(2)

2020-03-18  本文已影响0人  ftd黑马

对象深入学习,参数中有对象

直接撸代码:首先有两个实体类Person和Student

package com.example.myapplication;

import android.util.Log;

public class Student {

    private static final String TAG = Student.class.getSimpleName();

    public String name;
    public int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        Log.d(TAG, "setName: " + name);
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        Log.d(TAG, "setAge: " + age);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.example.myapplication;

import android.util.Log;

public class Person {

    private static final String TAG = Person.class.getSimpleName();

    public void setStudent(Student student) {
        Log.d(TAG, "setStudent: " + student.toString());
    }

}

然后MainActivity中调用jni方法,没有任何参数的
jni中代码如下:

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_test01(JNIEnv *env, jobject instance) {
    //我想在这个函数中,直接调用Person的setStudent方法

    //1,获取到全包名
    const char * person_class_str = "com/example/myapplication/Person";
    //2,获取到字节码对象
    jclass person_class = env->FindClass(person_class_str);
    //3,需要获取到jobject的对象
    jobject person = env->AllocObject(person_class);
    //4,调用person的setStudent方法,需要先获取methodId和签名

    const char * sig = "(Lcom/example/myapplication/Student;)V";
    jmethodID setStudent = env->GetMethodID(person_class,"setStudent",sig);

    //5,因为setStudent的参数是Student,所以还需要创建Student的对象
    const char *student_class_str = "com/example/myapplication/Student";
    jclass student_class = env->FindClass(student_class_str);
    jobject student = env->AllocObject(student_class);

    //6,给我们创建出来的student对象赋值
    sig = "(Ljava/lang/String;)V";
    jmethodID setName = env->GetMethodID(student_class,"setName",sig);
    jstring value = env->NewStringUTF("piter");
    env->CallVoidMethod(student,setName,value);

    sig = "(I)V";
    jmethodID setAge = env->GetMethodID(student_class, "setAge", sig);
    env->CallVoidMethod(student, setAge, 23);

    //7,调用Person的setStudent方法
    env->CallVoidMethod(person,setStudent,student);

    //8,回收
    env->DeleteLocalRef(student_class); // 遇到jclass  jobject,都要记得回收
    env->DeleteLocalRef(student);
    env->DeleteLocalRef(person);
    env->DeleteLocalRef(person_class);
}

运行结果为


image.png

全局引用和局部引用

随意来一个实体对象Dog

public class Dog {
    public Dog() {
        Log.d("Dog", "Dog: 构造方法被C++中直接实例化了....");
    }
}

jni中代码如下:

jclass dogClass;

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_testDog(JNIEnv *env, jobject instance) {
    // 局部引用:如果在函数里面,是在栈区,不用回收,函数结束,会自动回收
    if (dogClass == NULL) { // 方法刚进来满足,执行完后虽然被释放,但是还是不等于Null
        // 全局引用
        const char * dog_class_str = "com/example/myapplication/Dog";
        jclass temp = env->FindClass(dog_class_str);
        dogClass = static_cast<jclass>(env->NewGlobalRef(temp));
    }

    // Java构造方法的实例化
    const char * sig = "()V";
    const char * method = "<init>"; // Java构造方法的标识
    jmethodID init = env->GetMethodID(dogClass, method, sig);
    env->NewObject(dogClass, init); // 方法执行完毕,dogClass自动释放,但是不等于null,由于dogClass 是悬空的,直接报错
    //所以需要手动释放,但是手动释放完毕以后,dogClass还是不等于NULL,还需要手动改为Null
}

// 此函数就是为了 手动释放全局并且置为NULL
extern "C"
JNIEXPORT void JNICALL
Java_com_kevin_ndk09_1code_MainActivity_testUnDog(JNIEnv *env, jobject thiz) {
    // TODO: implement testUnDog()
    if(dogClass != NULL) {
        env->DeleteGlobalRef(dogClass);
        dogClass = NULL;
    }
}
上一篇下一篇

猜你喜欢

热点阅读