不同线程都需要通过 JavaVM 获取到的 JNIEnv 指针, 如果有两个线程有两个 env。 其中一个是jni接口自己传过来的,可以正常使用,正常获取kotlin中的class。但是通过 JavaVM 新获取的env 无法找到kotlin的class
1. 确保线程已附加到 JVM
确保每个线程在使用 JNIEnv
之前已附加到 JVM。可以在每个线程中调用 AttachCurrentThread
:
cpp
JavaVM* g_jvm = nullptr;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
g_jvm = vm;
return JNI_VERSION_1_6;
}
void someJNIFunction() {
JNIEnv* env;
if (g_jvm->AttachCurrentThread(&env, nullptr) != JNI_OK) {
// 处理错误
return;
}
// 使用 env 进行 JNI 调用
jclass cls = env->FindClass("com/example/YourKotlinClass");
if (cls == nullptr) {
// 处理类未找到的错误
}
// 线程使用完成后,分离线程
g_jvm->DetachCurrentThread();
}
2. 确保正确缓存类引用(关键:类要转化成全局引用即可给不同env使用)
确保类引用被正确缓存,并且在不同的线程中可用。可以在 JNI_OnLoad
中缓存类引用:
cpp
jclass g_yourKotlinClass; //这里是关键
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
g_jvm = vm;
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
// 这部分代码也可以写在 someJNIFunction 内。 不一定要写在JNI_OnLoad内
jclass localClass = env->FindClass("com/example/YourKotlinClass");
g_yourKotlinClass = (jclass) env->NewGlobalRef(localClass);
env->DeleteLocalRef(localClass);
return JNI_VERSION_1_6;
}
3. 例子:完整示例代码
cpp
#include <jni.h>
#include <android/log.h>
#define LOG_TAG "JNI_OnLoad"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
JavaVM* g_jvm = nullptr;
jclass g_yourKotlinClass = nullptr;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
g_jvm = vm;
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass localClass = env->FindClass("com/example/YourKotlinClass");
if (localClass == nullptr) {
return JNI_ERR; // 类加载失败
}
g_yourKotlinClass = (jclass) env->NewGlobalRef(localClass);
env->DeleteLocalRef(localClass);
return JNI_VERSION_1_6;
}
void someJNIFunction() {
JNIEnv* env;
if (g_jvm->AttachCurrentThread(&env, nullptr) != JNI_OK) {
// 处理错误
return;
}
if (g_yourKotlinClass == nullptr) {
LOGD("Kotlin class is null");
return;
}
jmethodID methodID = env->GetMethodID(g_yourKotlinClass, "yourMethodName", "()V");
if (methodID == nullptr) {
LOGD("Method ID not found");
return;
}
jobject obj = ... // 获取对象实例
env->CallVoidMethod(obj, methodID);
g_jvm->DetachCurrentThread();
}