Android JNI cpp文件創建 java bean 對象並返回

具體的使用方式都在代碼裏面了。

  • 首先準備一個 Student 和 Person
class Student {
    var name: String? = null;
    var age: Int? = 0;
}

class Person {

    constructor(){
        Log.e("Person", "無參構造器");
    }

    constructor(age: Int) {
        Log.e("Person", "age = $age");
    }

}
  • MainActivity中調用 JNI 層的代碼

class MainActivity : AppCompatActivity() {

    companion object {
        private const val TAG: String = "MainActivity";

        init {
            System.loadLibrary("native-lib")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

    }

    fun onClick(view: View) {
    	// JNI創建並返回 student 對象
        val student = useObjectFromJNI();
        Log.d(TAG, student.name);
        // JNI 通過構造器創建 Person 對象
        useConstructorINI();
    }
    private external fun stringFromJNI(): String
    private external fun useObjectFromJNI(): Student;
    private external fun useConstructorINI();
}

  • JNI 實現如下
  • 創建 Student
// ------頭文件
#include <jni.h>
#include <string>
#include <android/log.h>

#define TAG "ld"
#define log_debug(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__)
#define log_info(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)


// 創建並返回student
extern "C"
JNIEXPORT jobject JNICALL
Java_com_lu_jni_MainActivity_useObjectFromJNI(JNIEnv *env, jobject thiz) {

    // 使用 Java 類
    // 創建 Student 對象

    // student 文件路徑
    const char *student_path = "com/lu/jni/Student";
    // 獲取 class
    jclass student_class = env->FindClass(student_path);
        // 創建對象 AllocObject局部引用  分配新 Java 對象而不調用該對象的任何構造函數。返回	該對象的引用。	
    // NewGlobalRef是全局引用
    jobject student = env->AllocObject(student_class);
    // 獲取 jmethodID  (GetMethodID:第一個參數:jclass 第二個參數:要調用的方法名
    // 第三個參數 "(Ljava/lang/String;)V" 傳入 java/lang/String 參數 返回Void
    // V -> void (L ;)引用類型寫法 如果是Int 可以寫成 (I)V  也可以寫成  "(Ljava/lang/Integer;)V"
    jmethodID studentMethodId = env->GetMethodID(student_class, "setName", "(Ljava/lang/String;)V");
    jstring value = env->NewStringUTF("張三");
    // 調用 student 的 setName 方法
    env->CallVoidMethod(student, studentMethodId, value);

    // 通過構造方法創建 person 傳入student
    const char *person_path = "com/lu/jni/Person";
    jclass person = env->FindClass(person_path);

    return student;
}

  • 創建 Person
// 下面是創建 Person 並傳入構造器參數
jclass person;
extern "C"
JNIEXPORT void JNICALL
Java_com_lu_jni_MainActivity_useConstructorINI(JNIEnv *env, jobject thiz) {

    if (person == NULL) {
        log_debug("進入創建方法");
        const char *person_path = "com/lu/jni/Person";
        jclass tmpClass = env->FindClass(person_path);
        // NewGlobalRef 創建一個新的全局的引用,只能使用DeleteGlobalRef()函數銷燬這個全局引用
        person = static_cast<jclass>(env->NewGlobalRef(tmpClass));
    }
    // <init> 代表構造器創建
    const char *constructor = "<init>";
    // 獲取 jmethodID    ()V 代表無參數的構造器
    //jmethodID methodId = env->GetMethodID(person, constructor, "()V");
    //env->NewObject(person, methodId);

    // 如果是有參數的構造器  Person中傳入int類型參數
    jmethodID methodId1 = env->GetMethodID(person, constructor, "(I)V");
    jobject personObj = env->NewObject(person, methodId1, 100);

}

  • 使用結束後回收一下 即使是在棧中創建出棧會自動彈出,但是也建議手動刪除

// 使用完記得主動回收 如果是通過 new 來創建的對象是在堆內存中 一定要回收掉
void deleteClass(JNIEnv *env) {
    if (person != NULL) {
        // 釋放全局對象
        env->DeleteGlobalRef(person);
        person = NULL;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章