I'm writing an OpenGL C/C++ application which i'm porting to Android through Android NDK, JNI support. I'm having difficulties executing code from JAVA callback signaled from 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()
{
// force redraw
requestRender();
}
}
class OpenGLRenderer implements GLSurfaceView.Renderer
{
…
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
nativeObj.init(…);
nativeObj.cachejavaobject(JNIEnv *env, jobject obj); // for caching obj on native side
}
public void onSurfaceChanged(GL10 gl, int w, int h)
{
}
public void onDrawFrame(GL10 gl)
{
nativeObj.draw(…);
}
}
And in native code i have a function texturesLoaded() that is signaled when some textures are loaded completely on another thread and i need to force a refresh from nativeLib.draw(…) on the JAVA side. Here is how i do it :
I cache the JavaVM, jClass, jMethodID on 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)
{
// cache the java object
gJObjectCached = 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's 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!!!");
}
Result… from native side i get the class, i get the method, method gets called, but when it reaches/calls requestRender() inside(or trying to access any other member method of GLSurfaceView it crashes!)
I cannot try with CallStaticVoidMethod(gJClass, gjMethodID); because then i don't have access to requestRender();
Any ideas or opinions, maybe i'm doing something wrong here.
Thanks