从Native C / C ++代码调用JAVA类成员

我正在编写一个OpenGL C / C ++应用程序,我通过Android NDK,JNI支持移植到Android。 我在执行从本机发出信号的JAVA回调代码时遇到了困难。

这是代码:

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(…); } } 

在本机代码中,我有一个函数texturesLoaded(),当一些纹理完全加载到另一个线程上时我会发出信号,我需要在JAVA端强制刷新nativeLib.draw(…)。 我是这样做的:

我在JNI_OnLoad和gJObjectCached上缓存JavaVM,jClass,jMethodID

 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 AttachCurrentThread(&env, NULL); if(status 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; ... } 

然后在texturesLoaded()我做:

 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 AttachCurrentThread(&env, NULL); if(status CallVoidMethod(gJObjectCached, gJMethodID); LogNativeToAndroidExt("DONE!!!"); } 

结果……从本机方面我得到了类,我得到了方法,方法被调用,但是当它到达/调用requestRender()里面(或者试图访问GLSurfaceView的任何其他成员方法时它崩溃了!)

我无法尝试使用CallStaticVoidMethod(gJClass,gjMethodID); 因为那时我无法访问requestRender();

任何想法或意见,也许我在这里做错了。

谢谢

您需要创建您隐藏的类/对象的全局引用 。 您要保存的引用是本地引用 ,它们不能跨线程共享,并在运行时清除JNI本地引用堆栈时消失。

查看Sun / Oracle文档以获取全局和本地引用 ,并查看JNI方法JNIEnv::NewGlobalRefJNIEnv::DeleteGlobalRef

 gJClass = env->NewGlobalRef(env->FindClass( ... )); gJObjectCached = env->NewGlobalRef(obj); 

(编辑:原来你不需要方法ID的全局引用。)