문제

I have a GLSurfaceView created in a JAR file within my Android app. In the GLSurfaceView callback for onDrawFrame, I call a native C++ method via JNI. 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. So, I am trying to explicitly attach to the UI thread before doing so, but I am not successful.

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 :

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

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 ! 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

다른 팁

Your function is called from Java, therefore you should not call 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.

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. 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.

Finally, you are probably right, and calling an updateView() method, which requires the UI thread, from a GL thread, is not a good idea. You should probably issue a post, or send a message, or simply call runOnUIThread().

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top