Hello I'm writing a program for Android with Java and JNI.
I'm caching JavaVM*, a global ref jclass
and 2 methodsID
in the onLoad()
.
Then from myCallback()
, which is running on a separate thread, I get the ref to the environment using AttachCurrentThread()
and the cashed JavaVM*.
Then I want to pass a short[]
back to Java.
I'm getting the error: "accessed stale local reference"
here's my code:
JavaVM* mVm = NULL;
static jclass globalJavaReceiver = NULL;
jmethodID updatePlayerStatus = NULL;
jmethodID sendWaveData = NULL;
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
mVm = vm;
JNIEnv* env;
jclass nativeReceiver = NULL;
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
nativeReceiver = (*env)->FindClass(env,
"com/example/customviewcircles/nativeaudio/NativeReceiver");
if (nativeReceiver != NULL) {
globalJavaReceiver = (jclass)(*env)->NewGlobalRef(env, nativeReceiver);
if (globalJavaReceiver != NULL) {
updatePlayerStatus = (*env)->GetMethodID(env, globalJavaReceiver,
"myMethodName", "(I)V");
sendWaveData = (*env)->GetMethodID(env, globalJavaReceiver,
"mySecondMethosName", "([S)V");
}
}
return JNI_VERSION_1_6;
}
void myCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
JNIEnv* env;
(*mVm)->AttachCurrentThread(mVm, &env, NULL);
jshortArray javaArray = (*env)->NewShortArray(env, myBufferSize);
if (javaArray != NULL) {
(*env)->SetShortArrayRegion(env, javaArray, 0, myBufferSize,
myNativeShortArray);
}
jobject myObject = NULL;
if (globalJavaReceiver != NULL) {
if (sendWaveData != NULL) {
myObject = (*env)->NewObject(env, globalJavaReceiver,
sendWaveData);
if (myObject != NULL) {
(*env)->CallVoidMethod(env, myObject, sendWaveData,
javaArray);
// getting error
// JNI ERROR (app bug): accessed stale local reference 0x40995ec1 (index 22448 in a table of size 2)
// VM aborting
// A/libc(9813): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1), thread 9840 (AudioRecord)
}
}
}
(*mVm)->DetachCurrentThread(mVm);
}
what am I doing wrong?
thank you for your time
The problem here was that in :
myObject = (*env)->NewObject(env, globalJavaReceiver,
sendWaveData);
I was trying to create an object from a wrong class function, not from the constructor
So then I change this part in:
myObject = (*env)->NewObject(env, globalJavaReceiver,
nativeReceiverConstructor);
where nativeReceiverConstructor is the jmethodID from the class constructor. Then finally I've been able to do:
(*env)->CallVoidMethod(env, myObject, sendWaveData, javaArray);
where sendWaveData is the jmethodID from the function I want to call.
To pass the array I've then create a jshortArray and SetShortArrayRegion
Hope it helps