具体的使用方式都在代码里面了。
- 首先准备一个 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;
}
}