简体   繁体   English

在GLSurcfaceView回调期间从C ++调用回Java的问题

[英]Issue calling back into Java from C++ called during a GLSurcfaceView callback

I have a GLSurfaceView created in a JAR file within my Android app. 我在Android应用程序的JAR文件中创建了GLSurfaceView。 In the GLSurfaceView callback for onDrawFrame, I call a native C++ method via JNI. 在onDrawFrame的GLSurfaceView回调中,我通过JNI调用了本机C ++方法。 At this point, I believe I am in the GLThread, and in that native method, I am trying to call back into a Java class in my App's namespace and NOT into the namespace which made the call. 在这一点上,我相信我在GLThread中,并且在该本机方法中,我试图在我应用程序的名称空间中调用Java类,而不是在进行调用的名称空间中进行调用。 So, I am trying to explicitly attach to the UI thread before doing so, but I am not successful. 因此,我试图在这样做之前显式地附加到UI线程,但是我没有成功。

I am receiving the following error 我收到以下错误

W/dalvikvm( 4243): JNI WARNING: can't call Lcom/main/myapp;.updateView on instance of Lorg/myorg/myRenderer;
W/dalvikvm( 4243):              in Lorg/myorg/ImageRenderer;.renderImageFrame:()V (CallVoidMethodV)
I/dalvikvm( 4243): "GLThread 336" prio=5 tid=16 RUNNABLE
I/dalvikvm( 4243):   | group="main" sCount=0 dsCount=0 obj=0x418029f8 self=0x400988a8
I/dalvikvm( 4243):   | sysTid=4268 nice=0 sched=0/0 cgrp=apps handle=1362099424
I/dalvikvm( 4243):   | schedstat=( 0 0 0 ) utm=83 stm=71 core=1
I/dalvikvm( 4243):   at org.myorg.ImageRenderer.renderImageFrame(Native Method)
I/dalvikvm( 4243):   at org.myorg.ImageRenderer.onDrawFrame(ImageRenderer.java:93)
I/dalvikvm( 4243):   at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1516)
I/dalvikvm( 4243):   at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)

My C++ code looks like : 我的C ++代码如下所示:

JavaVM * jvm;

JNIEXPORT void JNICALL Java_org_myorg_ImageRenderer_renderImageFrame
  (JNIEnv *env, jobject jObj) {

 jvm->AttachCurrentThread(&env, 0);

        jclass javaClass = env->FindClass("com/main/myapp");
             if(javaClass == NULL){
                 LOGD("ERROR - CANNOT FIND CLASS");
             }

        jfloatArray viewArray = env->NewFloatArray(16);
        env->SetFloatArrayRegion(viewArray, 0, 16, glmatrix.data);
        jmethodID method = env->GetMethodID(javaClass, "updateView", "([F)V");
        if(method == NULL){
            LOGD("ERROR - CANNOT ACCESS METHOD");
        }

        env->CallVoidMethod(jObj, method, viewArray);
        env->DeleteLocalRef(viewArray);

jvm->DetachCurrentThread();

}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
    jvm = vm;
    return JNI_VERSION_1_2;
}

I am trying to call back into a Java class in my App's namespace and NOT into the namespace which made the call 我正在尝试在应用程序的命名空间中回调到Java类,而不是在进行调用的命名空间中回调

Yeah, that's the problem. 是的,就是这个问题。 You have looked up a methodID in class com.main.myapp but then you are trying to invoke that methodID on the original jobject instance of org.myorg.ImageRenderer ! 你已经看过了放在methodIDcom.main.myapp但你试图调用上的原jobject实例放在methodID org.myorg.ImageRenderer If you want to invoke a method from another "namespace", you have several options: 如果要从另一个“命名空间”调用方法,则有以下几种选择:

  1. the method must be static so that finding a class is enough and you don't need an object 该方法必须是静态的,以便找到一个类就足够了,并且您不需要对象
  2. the another object must be passed in the native method as a parameter 另一个对象必须在本机方法中作为参数传递
  3. the another object must be accessible as member/getter of the original object (which declared your native method) and then accessed via JNI method lookup and call 另一个对象必须作为原始对象的成员/获取者(声明了您的本机方法)才能访问,然后可以通过JNI方法查找和调用来访问

Your function is called from Java, therefore you should not call AttachCurrentThread . 您的函数是从Java调用的,因此您不应调用AttachCurrentThread

Your function receives from Java a reference to the org.myorg.myRenderer object, of which renderImageFrame() is a native method (every native method receives Java environment env as the first parameter, and its object reference, often denoted as thiz , as second parameter. 您的函数从Java接收到对org.myorg.myRenderer对象的引用,该对象的renderImageFrame()是本机方法(每个本机方法都将Java环境env接收为第一个参数,其对象引用通常称为thiz ,作为第二个参数参数。

If you want to call a Java method updateView() for the app object of class com.main.myapp , you should first obtain a reference to this object. 如果你想调用Java方法的UpdateView()的app类的对象com.main.myapp ,你应该首先获得该对象的引用。 The easiest way is to pass it as argument to your function, so now it will be declared as 最简单的方法是将其作为参数传递给函数,因此现在将其声明为

 JNIEXPORT void JNICALL Java_org_myorg_ImageRenderer_renderImageFrame(JNIEnv *env, jobject thiz, jobject app);

Alternatively, you may find the app object from thiz , if a reference to app is a field of the org.myorg.myRenderer , or is returend by some method of this class. 另外,如果对app的引用是org.myorg.myRenderer的字段,或者被此类的某些方法所破坏,则可以从thiz找到app对象。

Finally, you are probably right, and calling an updateView() method, which requires the UI thread, from a GL thread, is not a good idea. 最后,您可能是对的,从GL线程中调用需要UI线程的updateView()方法不是一个好主意。 You should probably issue a post , or send a message, or simply call runOnUIThread() . 您可能应该发布一个post ,或者发送一条消息,或者干脆调用runOnUIThread()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM