I am writing an OpenGL C / C ++ application that I port to Android via Android NDK, JNI support. I'm having difficulty executing code from a JAVA callback passed using native.
Here is the code:
class OpenGLSurfaceView extends GLSurfaceView { … public OpenGLSurfaceView(Context context, int deviceWidth, int deviceHeight) { super(context); nativeObj = new NativeLib(); mRenderer = new OpenGLRenderer(context, nativeObj, deviceWidth, deviceHeight); setRenderer(mRenderer); setRenderMode(RENDERMODE_WHEN_DIRTY); } … private void CallBack() {
And in my own code, I have a texturesLoaded () function that is signaled when some textures are loaded completely into another stream, and I need to force update from nativeLib.draw (...) on the JAVA side. Here is how I do it:
I cache JavaVM, jClass, jMethodID in JNI_OnLoad and gJObjectCached
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { gJVM = jvm; // cache the JavaVM pointer LogNativeToAndroidExt("JNILOAD!!!!!!!!!!"); JNIEnv *env; int status = gJVM->GetEnv((void **)&env, JNI_VERSION_1_6); if(status < 0) { LogNativeToAndroidExt("Failed to get JNI environment, assuming native thread"); status = gJVM->AttachCurrentThread(&env, NULL); if(status < 0) { LogNativeToAndroidExt("callback_handler: failed to attach current thread"); return JNI_ERR; } } gJClass = env->FindClass("com/android/newlineactivity/NewLineGLSurfaceView"); if(gJClass == NULL) { LogNativeToAndroidExt("Can't find Java class."); return JNI_ERR; } gJMethodID = env->GetMethodID(gJClass, "callback", "()V"); if(gJMethodID == NULL) { LogNativeToAndroidExt("Can't find Java method void callback()"); return JNI_ERR; } return JNI_VERSION_1_6;
}
JNIEXPORT void Java_com_android_OpenGL_NativeLib_cachejavaobject(JNIEnv* env, jobject obj) {
and then on texturesLoaded () I do:
void texturesLoaded() { // Cannot share a JNIEnv between threads. You should share the JavaVM, and use JavaVM->GetEnv to discover the thread JNIEnv JNIEnv *env = NULL; int status = gJVM->GetEnv((void **)&env, JNI_VERSION_1_6); if(status < 0) { LogNativeToAndroidExt("callback_handler: failed to get JNI environment, assuming native thread"); status = gJVM->AttachCurrentThread(&env, NULL); if(status < 0) { LogNativeToAndroidExt("callback_handler: failed to attach current thread"); return; } } LogNativeToAndroidExt("Calling JAVA method from NATIVE C/C++"); env->CallVoidMethod(gJObjectCached, gJMethodID); LogNativeToAndroidExt("DONE!!!"); }
The result ... on the native side, I get the class, I get the method, the method is called, but when it reaches / calls requestRender () inside (or tries to access any other method of the GLSurfaceView member, it will work!)
I can not try with CallStaticVoidMethod (gJClass, gjMethodID); because then I do not have access to requestRender ();
Any ideas or opinions, maybe I'm doing something wrong here.
thanks