具體的使用方式都在代碼裏面了。
- 首先準備一個 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;
}
}