Unable to get JNIEnv* value in arbitrary context
我对NDK有问题。
在我的JNI_OnLoad方法中,我缓存了JavaVm指针,调用该方法的类以及稍后将在以下方法上使用的方法ID:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved){ JNIEnv *env; cachedJVM = jvm; if((*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_6)){ LOG_ERROR("Could not get JNIEnv*"); return JNI_ERR; } javaClass = (*env)->FindClass(env,"org/test/opensl/AudioProcessor"); if(javaClass == NULL){ LOG_ERROR("Could not get java class"); return JNI_ERR; } javaCallbackMID = (*env)->GetMethodID(env, javaClass,"enqueueAudio","([B)V"); if(javaCallbackMID == NULL){ LOG_ERROR("Could not get method identifier"); return JNI_ERR; } return JNI_VERSION_1_6; } |
我有一个定义如下的实用工具小方法,应该为我提供一个指向JNIEnv的指针:
1 2 3 4 5 | JNIEnv* JNU_GetEnv(){ JNIEnv* env; (*cachedJVM)->GetEnv(cachedJVM, (void**)&env, JNI_VERSION_1_6); return env; } |
最后,我有一个来自OpenSL ES
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | void recorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context){ SLresult result; JNIEnv* env; recorderContext* thisContext = (recorderContext*)context; env = JNU_GetEnv(); if(env == NULL){ LOG_ERROR("Could not get JNIEnv*"); return; } jbyteArray data = (*env)->NewByteArray(env, MAX_PACKET_SIZE); if(data == NULL){ LOG_ERROR("No memory could be allocated for buffer"); return; } (*env)->SetByteArrayRegion(env, data, 0, MAX_PACKET_SIZE, recorderBuffer); (*env)->CallByteMethodA(env, thisContext->caller, javaCallbackMID, data); (*env)->DeleteLocalRef(env, data); result = (*bq)->Enqueue(bq, recorderBuffer, RECORDER_FRAMES * sizeof(jbyte)); checkError(result,"Unable to enqueue new buffer"); } |
其中回调方法的上下文参数仅保留对调用本机方法的对象的引用。这是一个自定义的结构,如下所示:
1 2 3 | typedef struct recorderContext{ jobject caller; } recorderContext; |
但是,每次我尝试运行此命令时,都会从回调方法中收到
我的问题基本上可以归结为:为什么我可以在JNI_OnLoad方法中获得指向JNIEnv的指针,而在recorderCallback中却不能,因为两者都使用相同的Java VM指针来获取JNIEnv?
我需要此回调以将记录的音频传递回我的Java层以进行进一步处理...
Why can I get a pointer to the JNIEnv
in the JNI_OnLoad method, but not in
the recorderCallback, as both use the
same Java VM pointer to get the
JNIEnv?
因为回调发生在某些本机线程上,与加载库的VM线程不同。 JNI实现为每个线程维护一个
请参阅http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html
注意事项:此答案假定使用正确的Java。您看到的问题表明Dalvik的行为与JVM相同。