Android JNI如何在C++独立线程中调用MainActivity对象的Java方法
错误根本原因
- 你直接存储的
jobjecte(也就是MainActivity实例)是局部引用,JNI方法Java_com_myname_mydetails_myfunction_MainActivity_startItUp执行结束后,这个局部引用就会被JVM自动回收,后续子线程访问的就是已经失效的引用,自然会报invalid jobject错误 - 额外提醒:不要跨线程存储
JNIEnv指针,JNIEnv是线程绑定的,只在所属线程有效,跨线程使用必报错,你子线程已经通过Attach拿到了当前线程的Env,完全不需要提前存储全局Env
解决步骤
1. 将MainActivity的局部引用转为全局引用存储
你在JNI入口方法里拿到MainActivity的jobject之后,调用env->NewGlobalRef把它转为全局引用再存到C++对象里,全局引用只有你手动调用DeleteGlobalRef才会被回收,跨线程访问是安全的。
修改你的JNI入口方法:
extern "C" JNIEXPORT jstring JNICALL Java_com_myname_mydetails_myfunction_MainActivity_startItUp( JNIEnv* env, _jobject *jobjecte /* this */) { jint err = env->GetJavaVM(&jvm); // 把局部引用转为全局引用再传递 jobject globalMainActivity = env->NewGlobalRef(jobjecte); startThings(jvm, globalMainActivity); // 不需要传递Env,子线程自己Attach获取即可 return env->NewStringUTF(hello.c_str()); }
然后修改setJVM方法,去掉存储Env的逻辑:
void setJVM( JavaVM *_jvm, _jobject *_mainActivityGlobal){ jvm = _jvm; mainActivity = _mainActivityGlobal; // 存储的是全局引用 }
2. 子线程中正常使用全局引用即可
你现有的子线程逻辑不用大改,只要保证存储的是全局引用就不会报错:
void myclass::mymethod(int64_t _profile){ JNIEnv *env = NULL; JavaVMAttachArgs args; args.version = JNI_VERSION_1_6; args.name = NULL; args.group = NULL; jvm->AttachCurrentThread(&env, &args); // 这里用全局的mainActivity就不会报错了 jclass clazz = env->GetObjectClass(mainActivity); // 接下来找方法ID、调用方法的逻辑正常写即可,比如你要回传字符串: jmethodID updateUiMethod = env->GetMethodID(clazz, "updateUiText", "(Ljava/lang/String;)V"); jstring content = env->NewStringUTF("你要回传的字符串"); env->CallVoidMethod(mainActivity, updateUiMethod, content); // 注意:如果这个线程是一次性的,用完要执行Detach释放资源 jvm->DetachCurrentThread(); }
3. 规避内存泄漏
当MainActivity销毁的时候(比如用户退出APP),你要主动调用JNI方法释放全局引用,避免内存泄漏:
extern "C" JNIEXPORT void JNICALL Java_com_myname_mydetails_myfunction_MainActivity_releaseRef( JNIEnv* env, _jobject *thiz) { if (mainActivity != NULL) { env->DeleteGlobalRef(mainActivity); mainActivity = NULL; } }
然后在MainActivity的onDestroy生命周期里调用这个releaseRef方法即可。
额外注意点
如果要在子线程触发的Java方法里更新界面控件,Java侧的updateUiText方法里要记得用runOnUiThread切换到主线程操作,否则会触发Android子线程无法更新UI的错误。
内容的提问来源于stack exchange,提问作者confused
相关产品推荐
相关产品推荐

