JNI回调用中不同线程的env无法找到正确的kotlin的class

不同线程都需要通过 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();
}
相关推荐
省四收割者11 分钟前
Go语言入门(20)-nil
开发语言·vscode·golang
19岁开始学习11 分钟前
Go语言中的Zap日志库
开发语言·golang·xcode
数据知道11 分钟前
Go基础:用Go语言操作MongoDB详解
服务器·开发语言·数据库·后端·mongodb·golang·go语言
爱喝白开水a19 分钟前
2025时序数据库选型,从架构基因到AI赋能来解析
开发语言·数据库·人工智能·架构·langchain·transformer·时序数据库
朝新_20 分钟前
【EE初阶 - 网络原理】网络通信
java·开发语言·网络·php·javaee
TeleostNaCl25 分钟前
使用 jintellitype 库在 Java 程序中实现监听 Windows 全局快捷键(热键)
java·开发语言·windows·经验分享·kotlin·电脑
盛世隐者1 小时前
python包管理器——uv
开发语言·python·uv
细节控菜鸡1 小时前
【2025最新】ArcGIS for JS 实现地图卷帘效果
开发语言·javascript·arcgis
liulilittle2 小时前
网络编程基础算法剖析:从字节序转换到CIDR掩码计算
开发语言·网络·c++·算法·通信
代码村新手2 小时前
C语言-字符函数和字符串函数
c语言·开发语言