20 JNI - c++层 操作 java 层对象

111 阅读3分钟

Android Ndk 学习笔记(目录)

1 1 int 基本类型 , String 引用对象类型, int[] array 类型 String [] 引用对象数组类型

 public native void testArrayAction(int count, String textInfo, int[] ints, String[] strs); // String引用类型,玩数组
public void test01(View view) {
        int[] ints = new int[]{18,28,38,48,58,68}; // 基本类型的数组

        String[] strs = new String[]{"小龙","小杰","小霸"}; // 对象类型的数组

        testArrayAction(99, "你好", ints, strs);

        for (int anInt : ints) {
            Log.i("info", "Java test01: anInt:" + anInt);
        }

        for (String item : strs) {
            Log.i("info", "Java test01: strings:" + item);
        }

    }
extern "C"
JNIEXPORT void JNICALL
Java_com_cn_mynativestudy_MainActivity_testArrayAction(
        JNIEnv *env,
        jobject thiz,
        jint count,
        jstring text_info,
        jintArray ints,
        jobjectArray strs) {

    // C++ jint  对应  java int
    // C++ jstring  对应  java String 或 Object
    // C++ jintArray  对应  java int[]
    // C++ jobjectArray  对应  java String[] 或 Object []

    //1 JNI 中 jint 可以直接赋值 给 c++ 中 int
    int c_int = count  ;
    LOGI("int = %d",c_int);

    const  char * c_string1 = env->GetStringUTFChars(text_info,NULL);
    LOGI("string1 = %s",c_string1);

    char * c_string2 = const_cast<char *>(env->GetStringUTFChars(text_info, NULL));
    LOGI("string2 = %s",c_string2);


    env->ReleaseStringUTFChars(text_info,c_string1);
    env->ReleaseStringUTFChars(text_info,c_string2);


    int * intArrays = env->GetIntArrayElements(ints ,NULL);
    for (int i = 0; i < env->GetArrayLength(ints); ++i) {

        *(intArrays + i)+1;
        LOGI("ints[%d] = %d",i,*(intArrays +i));
    }

    /**
     *  刷新 java 层 数据
     * 0:           刷新Java数组,并 释放C++层数组
     * JNI_COMMIT:  只提交 只刷新Java数组,不释放C++层数组
     * JNI_ABORT:   只释放C++层数组
     */
    env->ReleaseIntArrayElements(ints,intArrays,0);

    jsize str_size = env->GetArrayLength(strs);

    for (int i = 0; i <str_size; ++i) {
        jstring j_str = static_cast<jstring>(env->GetObjectArrayElement(strs , i));
        const  char * item = env->GetStringUTFChars(j_str,NULL);
        LOGI("strs[%d] = %s",i,item);
        env->ReleaseStringUTFChars(j_str,item);
    }


}

2 传递引用类型,传递对象

public native void putObject(Student student, String str); // 传递引用类型,传递对象
  public void test02(View view) {
        Student student = new Student(); // Java new
        student.name = "史泰龙";
        student.age = 88;
        putObject(student, "九阳神功");
    }
extern "C"
JNIEXPORT void JNICALL
Java_com_cn_mynativestudy_MainActivity_putObject(JNIEnv *env, jobject thiz, jobject student,
                                                 jstring str) {

    jclass j_student = env->GetObjectClass(student);
    char * classpath = "com/cn/mynativestudy/c19/Student";
    jclass j_student2 = env->FindClass(classpath);

    jmethodID  j_setName1 = env->GetMethodID(j_student,"setName", "(Ljava/lang/String;)V");
    jmethodID  j_setName2 = env->GetMethodID(j_student2,"setName", "(Ljava/lang/String;)V");

    jmethodID  j_getName1 = env->GetMethodID(j_student,"getName", "()Ljava/lang/String;");
    jmethodID  j_getName2 = env->GetMethodID(j_student2,"getName", "()Ljava/lang/String;");

    jstring name1 = env->NewStringUTF("哇啊啊");
    env->CallVoidMethod(student,j_setName1,name1);

    jstring j_getname1 = static_cast<jstring>(env->CallObjectMethod(student, j_getName1));
    char * c_getname1 = const_cast<char *>(env->GetStringUTFChars(j_getname1, NULL));
    LOGI("c_getname1 = %s",c_getname1);


    jstring name2 = env->NewStringUTF("呼哈哈");
    env->CallVoidMethod(student,j_setName2,name2);

    jstring j_getname2 = static_cast<jstring>(env->CallObjectMethod(student, j_getName2));
    char * c_getname2 = const_cast<char *>(env->GetStringUTFChars(j_getname2, NULL));
    LOGI("c_getname2 = %s",c_getname2);

    jmethodID showInfo = env->GetStaticMethodID(j_student, "showInfo", "(Ljava/lang/String;)V");
    jstring jstringValue = env->NewStringUTF("我是C++");
    env->CallStaticVoidMethod(j_student, showInfo, jstringValue);

}

3 通过包名创建对象

public native void insertObject();
public void test03(View view) {
        insertObject();
    }
extern "C"
JNIEXPORT void JNICALL
Java_com_cn_mynativestudy_MainActivity_insertObject(JNIEnv *env, jobject thiz) {

    char * classpath = "com/cn/mynativestudy/c19/Student";
    jclass j_student_class = env->FindClass(classpath);

    jmethodID  j_setName1 = env->GetMethodID(j_student_class,"setName", "(Ljava/lang/String;)V");
    jstring name1 = env->NewStringUTF("哇啊啊");

    // AllocObject 只实例化对象,不会调用对象的构造函数
    jobject j_student_obj = env->AllocObject(j_student_class);
    env->CallVoidMethod(j_student_obj,j_setName1,name1);


    char * person_class_path = "com/cn/mynativestudy/c19/Person";
    jclass j_person_class = env->FindClass(person_class_path);

    jmethodID  j_setStudent = env->GetMethodID(j_person_class,"setStudent", "(Lcom/cn/mynativestudy/c19/Student;)V");
    jobject j_person_obj = env->AllocObject(j_person_class);
    env->CallVoidMethod(j_person_obj,j_setStudent,j_student_obj);

    jmethodID  j_static_putStudent = env->GetStaticMethodID(j_person_class,"putStudent","(Lcom/cn/mynativestudy/c19/Student;)V");
    env->CallStaticVoidMethod(j_person_class,j_static_putStudent,j_student_obj);


    env->DeleteLocalRef(j_student_obj);
    env->DeleteLocalRef(j_student_class);
    env->DeleteLocalRef(j_person_obj);
    env->DeleteLocalRef(j_person_class);
}

4 测试引用

public native void testQuote(); // 测试引用
public void test04(View view) {
        testQuote();
    }
jclass dogClass; // 你以为这个是全局引用,实际上他还是局部引用

extern "C"
JNIEXPORT void JNICALL
Java_com_cn_mynativestudy_MainActivity_testQuote(JNIEnv *env, jobject thiz) {
    if (NULL == dogClass) {
        /*const char * dogStr = "com/derry/as_jni_project/Dog";
        dogClass = env->FindClass(dogStr);*/
        // 升级全局引用: JNI函数结束也不释放,反正就是不释放,必须手动释放   -----
        //相当于: C++ 对象 new、手动delete
        const char * dogStr = "com/cn/mynativestudy/c19/Dog";
        jclass temp = env->FindClass(dogStr);
        dogClass = static_cast<jclass>(env->NewGlobalRef(temp)); // 提升全局引用
        // 记住:用完了,如果不用了,马上释放,C C++ 工程师的赞美
        env->DeleteLocalRef(temp);
    }


    jmethodID  method1 = env->GetMethodID(dogClass,"<init>","()V");
    jobject obj1 = env->NewObject(dogClass,method1);

    jmethodID  method2 = env->GetMethodID(dogClass,"<init>","(I)V");
    obj1 = env->NewObject(dogClass,method2,100);

    jmethodID  method3 = env->GetMethodID(dogClass,"<init>","(II)V");
    obj1 = env->NewObject(dogClass,method3,200,300);

    env->DeleteLocalRef(obj1);

}

5 释放全局引用

public native void delQuote(); // 释放全局引用
public void test05(View view) {
        delQuote(); // 必须释放全局引用
    }
extern "C"
JNIEXPORT void JNICALL
Java_com_cn_mynativestudy_MainActivity_delQuote(JNIEnv *env, jobject thiz) {

    if (dogClass != NULL) {
        LOGE("全局引用释放完毕,上面的按钮已经失去全局引用,再次点击会报错");
        env->DeleteGlobalRef(dogClass);
        dogClass = NULL; // 最好给一个NULL,指向NULL的地址,不要去成为悬空指针,为了好判断悬空指针的出现
    }
}

6 extern 关键字 ,方便扩展

extern int age; // 声明age
extern void show(); // 声明show函数 

在这里插入图片描述
在这里插入图片描述