Android 从本机C/C+;调用JAVA类成员+;代码
我正在编写一个OpenGL C/C++应用程序,通过Android NDK和JNI支持将其移植到Android。我在从本机发出的JAVA回调执行代码时遇到困难 代码如下:Android 从本机C/C+;调用JAVA类成员+;代码,android,java-native-interface,android-ndk,Android,Java Native Interface,Android Ndk,我正在编写一个OpenGL C/C++应用程序,通过Android NDK和JNI支持将其移植到Android。我在从本机发出的JAVA回调执行代码时遇到困难 代码如下: class OpenGLSurfaceView extends GLSurfaceView { … public OpenGLSurfaceView(Context context, int deviceWidth, int deviceHeight) { super(context);
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上缓存JavaVM、jClass、jMethodID和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;
然后在texturesLoaded()上,我执行以下操作:
void texturesLoaded()
{
//无法在线程之间共享JNIEnv。您应该共享JavaVM,并使用JavaVM->GetEnv来发现线程的JNIEnv
JNIEnv*env=NULL;
int status=gJVM->GetEnv((void**)和env,JNI\u版本1\u 6);
如果(状态<0)
{
LogNativeToAndroText(“回调_处理程序:无法获取JNI环境,假设为本机线程”);
status=gJVM->AttachCurrentThread(&env,NULL);
如果(状态<0)
{
LogNativeToAndroText(“回调处理程序:未能附加当前线程”);
返回;
}
}
LogNativeToAndroText(“从本机C/C++调用JAVA方法”);
env->CallVoidMethod(gJObjectCached,gJMethodID);
LognativeToAndroText(“完成!!!”);
}
结果…从本机端我得到了类,得到了方法,调用了方法,但当它到达/调用内部的requestRender()时(或试图访问GLSurfaceView的任何其他成员方法时,它崩溃了!)
我无法尝试使用CallStaticVoidMethod(gJClass,gjMethodID);因为这样我就没有访问requestRender()的权限
任何想法或意见,也许我做错了什么
谢谢您需要创建对隐藏的类/对象的全局引用。您保存的引用是本地引用,不能跨线程共享,并且在运行时清理JNI本地引用堆栈时会消失
检查,并检查JNI方法和
gJClass=env->NewGlobalRef(env->FindClass(…);
gJObjectCached=env->NewGlobalRef(obj);
(编辑:原来方法ID不需要全局引用。)
requestRender()是Java语言,所以崩溃通常伴随着异常。你能说说那个例外是什么吗。Android ADB日志应该会显示这些信息。你的答案很有用,但对我的问题没有帮助。我的全局缓存jclass和jmethodID是有效的,我可以访问我的JAVA回调,它是该类的一个成员(不是静态的)。问题是我无法从该回调调用该类的另一个成员,因为我认为我缓存的jobject没有指向:“com/android/newlineactivity/NewLineGLSurfaceView”,因为我可能将它缓存在另一个JENV中。因此,对于静态成员,这是有效的:env->CallStaticVoidMethod(gJClass,gJMethodID);但对于一个非静态的方法,它不是:env->CallVoidMethod(gJObjectCached,gJMethodID);有意义吗?gJObjectCached
是全局引用,还是您只是存储了传递到cachejavaobject
的本地引用?它是全局引用,在我调用env->CallVoidMethod(gJObjectCached,gJMethodID)时有效;但回调()在内部调用requestRender()时崩溃。我甚至尝试了jobject jobj=env->NewObject(gJClass,gJMethodID);并通过它,希望有了正确的env、gjClass和gJMethodID,我可以调用这个方法,它就会工作。。。方法被调用,但在requestRender()处再次崩溃;六羟甲基三聚氰胺六甲醚。。。你的问题有点让人困惑。。。jobject是缓存的;在我的.cpp文件中声明为全局,我在其中存储传递到cachejavaobject的本地引用,使用:JNIEXPORT void Java_com_android_OpenGL_NativeLib_cachejavaobject(JNIEnv env,jobject obj){//缓存Java对象gJObjectCached=env->NewGlobalRef(obj);lognativeToAndroText(“gObjectCached global”)}如果您正在执行gJObjectCached=env->NewGlobalRef(obj)
,那么您正在存储一个全局引用,这是您应该执行的操作。如果这样做之后事情仍然不起作用,恐怕我没有建议了。
JNIEXPORT void Java_com_android_OpenGL_NativeLib_cachejavaobject(JNIEnv* env, jobject obj)
{
// cache the java object
gJObjectCached = obj;
...
}
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!!!");
}