当前位置: 首页 > news >正文

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

不同线程都需要通过 JavaVM 获取到的 JNIEnv 指针, 如果有两个线程有两个 env。 其中一个是jni接口自己传过来的,可以正常使用,正常获取kotlin中的class。但是通过 JavaVM 新获取的env 无法找到kotlin的class

1. 确保线程已附加到 JVM

确保每个线程在使用 JNIEnv 之前已附加到 JVM。可以在每个线程中调用 AttachCurrentThread

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 中缓存类引用:

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. 例子:完整示例代码

#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();
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Vite 常用插件配置:自动导入+自动注册组件+动态创建图标+设置组件名
  • C 语言基础概念总结
  • 在没有源程序的情况时,如何通过控制鼠标按钮控制电脑exe程序?
  • Android小技巧:利用动态代理自动切换线程(续)
  • wodpress设置固定链接的方式和好处【SEO优化】
  • Qt遇到qt自身组件找不到
  • Firefox扩展程序和Java通信
  • C# Task.WaitAll 的用法
  • BGP选路之Local Preference
  • table car vs. table cars:数据库命名用单数还是复数?
  • OpenCV图像滤波(1)双边滤波函数bilateralFilter的使用
  • 小规模的LLMS
  • C# 使用pythonnet 迁入 python 初始化错误解决办法
  • GO版本更新
  • [Meachines] Lame smbd3.0-RCE
  • 78. Subsets
  • ERLANG 网工修炼笔记 ---- UDP
  • IDEA 插件开发入门教程
  • IndexedDB
  • JAVA SE 6 GC调优笔记
  • java第三方包学习之lombok
  • Java精华积累:初学者都应该搞懂的问题
  • Laravel Telescope:优雅的应用调试工具
  • React的组件模式
  • Vue2.0 实现互斥
  • 番外篇1:在Windows环境下安装JDK
  • 浮动相关
  • 汉诺塔算法
  • 如何选择开源的机器学习框架?
  • 小程序 setData 学问多
  • 用jquery写贪吃蛇
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结
  • #android不同版本废弃api,新api。
  • #define
  • #pragma pack(1)
  • #如何使用 Qt 5.6 在 Android 上启用 NFC
  • $.ajax()参数及用法
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (02)vite环境变量配置
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (javaweb)Http协议
  • (JS基础)String 类型
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (个人笔记质量不佳)SQL 左连接、右连接、内连接的区别
  • (十一)图像的罗伯特梯度锐化
  • (算法)硬币问题
  • (五)activiti-modeler 编辑器初步优化
  • (原)本想说脏话,奈何已放下
  • (转)Google的Objective-C编码规范
  • (转)负载均衡,回话保持,cookie
  • (轉貼)《OOD启思录》:61条面向对象设计的经验原则 (OO)
  • .net core webapi Startup 注入ConfigurePrimaryHttpMessageHandler