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();
}
相关推荐
Lei活在当下3 小时前
【项目踩坑实录】并发环境下,Glide缓存引起的图片加载异常
android·debug·glide
醇氧3 小时前
【Windows】优雅启动:解析一个 Java 服务的后台启动脚本
java·开发语言·windows
hetao17338374 小时前
2025-12-12~14 hetao1733837的刷题笔记
数据结构·c++·笔记·算法
椰子今天很可爱4 小时前
五种I/O模型与多路转接
linux·c语言·c++
MapGIS技术支持4 小时前
MapGIS Objects Java计算一个三维点到平面的距离
java·开发语言·平面·制图·mapgis
程序员zgh4 小时前
C++ 互斥锁、读写锁、原子操作、条件变量
c语言·开发语言·jvm·c++
小灰灰搞电子5 小时前
Qt 重写QRadioButton实现动态radioButton源码分享
开发语言·qt·命令模式
by__csdn5 小时前
Vue3 setup()函数终极攻略:从入门到精通
开发语言·前端·javascript·vue.js·性能优化·typescript·ecmascript
喵了meme5 小时前
C语言实战5
c语言·开发语言
廋到被风吹走5 小时前
【Java】常用设计模式及应用场景详解
java·开发语言·设计模式