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();
}
相关推荐
明月看潮生9 分钟前
青少年编程与数学 02-003 Go语言网络编程 15课题、Go语言URL编程
开发语言·网络·青少年编程·golang·编程与数学
Winston Wood11 分钟前
Android Parcelable和Serializable的区别与联系
android·序列化
清风徐来辽15 分钟前
Android 项目模型配置管理
android
南宫理的日知录20 分钟前
99、Python并发编程:多线程的问题、临界资源以及同步机制
开发语言·python·学习·编程学习
逊嘘37 分钟前
【Java语言】抽象类与接口
java·开发语言·jvm
van叶~39 分钟前
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
c++·算法
Half-up39 分钟前
C语言心型代码解析
c语言·开发语言
帅得不敢出门42 分钟前
Gradle命令编译Android Studio工程项目并签名
android·ide·android studio·gradlew
knighthood20011 小时前
解决:ros进行gazebo仿真,rviz没有显示传感器数据
c++·ubuntu·ros
Source.Liu1 小时前
【用Rust写CAD】第二章 第四节 函数
开发语言·rust