Because the callback happens on some native thread, different from the VM thread which loads the library. The JNI implementation maintains a JNIEnvper thread, and puts the pointer in thread-local storage. It is only initialized for native threads which are attached to the VM. You need to call AttachCurrentThread()(or more probably AttachCurrentThreadAsDaemon()) inside the callback to get a JNIEnvpointer valid for that thread. This attaches the thread to the VM on the first call and is a nop thereafter.
android的每个应用程序对应一个虚拟机。所以每个应用程序会有一个jvm,也就是jvm是应用程序范围内的。而jenv却是线程范围内的,每个线程一个。native线程而只有native线程函数需要attach。所以我们在本地调用时要先用getenv查询线程是否拥有jenv,如果拥有则不需要attach,否则需要attach。
bool myAttachCurrentThread(void** env )
{
int status = 0;
status = gs_jvm->GetEnv(env,JNI_VERSION_1_4);
if(status<0)
{
gs_jvm->AttachCurrentThread((JNIEnv**)env, NULL);
return true;
}
return false;
}