我有一个使用NDK的Android应用程序,它是一个普通的Android Java应用程序,具有常规UI和C++核心。在核心代码中,我需要调用Java方法,这意味着我需要为该线程获取一个JNIEnv*,这又意味着我需要调用JavaVM-> AttachCurrentThread()来获取有效的env。
以前,我只是在做AttachCurrentThread并没有去解除绑定。在Dalvik中运行很好,但是ART会在一个调用了AttachCurrentThread的线程退出而没有调用DetachCurrentThread时立即终止应用程序。所以我阅读了JNI参考文献,确实说我必须调用DetachCurrentThread。但是当我这样做时,ART会用以下信息中止应用程序:
尝试在仍在运行代码时取消分离
那么问题出在哪里?怎样正确地调用DetachCurrentThread?
以前,我只是在做AttachCurrentThread并没有去解除绑定。在Dalvik中运行很好,但是ART会在一个调用了AttachCurrentThread的线程退出而没有调用DetachCurrentThread时立即终止应用程序。所以我阅读了JNI参考文献,确实说我必须调用DetachCurrentThread。但是当我这样做时,ART会用以下信息中止应用程序:
尝试在仍在运行代码时取消分离
那么问题出在哪里?怎样正确地调用DetachCurrentThread?
JavaVM->GetEnv(void** penv, jint version);
来获取JNIEnv
? - alijandroGetEnv
将失败(它会返回JNI_EDETACHED
并给你一个NULL JNIEnv*
)。然而,先调用GetEnv
似乎是个好主意,只有在它返回JNI_EDETACHED
时才调用AttachCurrentThread
。 - MichaelAttachCurrentThread
是无操作的。因此,我认为AttachCurrentThread
已经实现了你所建议的功能。 - Violet GiraffeAttachCurrentThread
是否实际上已经将线程附加是很重要的,这样你就不会在无操作附加后调用DetachCurrentThread
。我最终编写了一个C++类,在构造时从GetEnv
或AttachCurrentThread
获取JNIEnv*
,并且仅在构造函数必须调用AttachCurrentThread
时在析构函数中调用DetachCurrentThread
。这样,我可以声明这些对象,使用它们的JNIEnv*
,并且当对象超出范围时自动分离线程。 - Michaeldetach
。我认为这不应该发生,因为每次请求JNIEnv*
时我都会调用attach
,并且当我完成后我会调用detach
(通过C++ RAII风格的包装器来实现)。但我会尝试你的方法,这肯定更安全、更干净。 - Violet Giraffe