Android NDK:从JNI C类调用Java方法

10

我有一个JNI方法,其中我试图调用Java方法。这是我的JNI代码:

void DummySink::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes,
                  struct timeval presentationTime, unsigned /*durationInMicroseconds*/) {

     __android_log_print(ANDROID_LOG_VERBOSE, "RTSP", "Frame: %c", propRec->sPropBytes);
     jmethodID mid;
     jclass handlerClass = env9->FindClass("ob/android/Stream");
     if (handlerClass == NULL) {
         __android_log_print(ANDROID_LOG_VERBOSE, "RTSP-Error", "Class");
     }
     mid = env9->GetMethodID(handlerClass, "onResponse", "([B)V");
     if (mid == NULL) {
         __android_log_print(ANDROID_LOG_VERBOSE, "RTSP-Error", "Method");
     }

     jbyteArray jbArray = env9->NewByteArray((int)propRec->sPropLength);
     env9->SetByteArrayRegion(jbArray, 0, (int)propRec->sPropLength, (jbyte*)propRec->sPropBytes);

     //jobject theClass = env9->FindClass("ob/android/Stream");

     env9->CallVoidMethod(handlerClass, mid, jbArray);

}

这是我的Java代码:
public void onResponse(byte[] str) 
    { 
        Log.v("Response", "Java");
    }

我遇到了以下的崩溃问题:
03-08 16:01:05.915: W/dalvikvm(17552): JNI WARNING: can't call Lob/android/Stream;.onResponse on instance of Ljava/lang/Class;
03-08 16:01:05.915: W/dalvikvm(17552):              in Lob/android/Stream;.stream:()V (CallVoidMethodV)

应用Mah的答案后,我收到了以下异常。
03-08 16:40:20.646: W/dalvikvm(4076): JNI WARNING: JNI method called with exception pending
03-08 16:40:20.646: W/dalvikvm(4076):              in Lob/android/Stream;.stream:()V (NewByteArray)
03-08 16:40:20.646: W/dalvikvm(4076): Pending exception is:
03-08 16:40:20.646: I/dalvikvm(4076): java.lang.NoSuchMethodError: no method with name='onResponse' signature='([B)V' in class Lob/android/Stream;
03-08 16:40:20.646: I/dalvikvm(4076):   at ob.android.Stream.stream(Native Method)
03-08 16:40:20.646: I/dalvikvm(4076):   at ob.android.Stream.<init>(Stream.java:28)
03-08 16:40:20.654: I/dalvikvm(4076):   at ob.android.MainActivity.startRecording(MainActivity.java:203)

现在onResponse方法是静态的。


在任何可能抛出异常的JNI调用之后,您必须检查并处理异常。CallVoidMethod是一个典型的例子。请参阅http://developer.android.com/training/articles/perf-jni.html#exceptions。 - fadden
2个回答

11
你的Java方法是实例方法(非静态),但你的本机代码没有引用到任何特定实例的ob.android.Stream来调用onResponse()
在调用CallVoidMethod()时,第一个参数应该是你正在运行方法的实例(对象),而不是类本身。如果你使用CallStaticVoidMethod(),则会使用类本身。

当我更改为以下代码时,是否有可能提供更多细节:jmethodID method = env->GetMethodID(obj, "playA", "()V");我看到了以下错误信息:error: invalid conversion from 'jobject {aka _jobject*}' to 'jclass {aka _jclass*}' [-fpermissive] - Jackie
@Jackie GetMethodId() 需要从 class 中获取方法 ID,而不是像你现在使用的那样从一个 object 中获取。如果你还没有该对象的类可用,可以通过使用 GetObjectClass() 从该 obj 中获取它。 - mah
更正:CallVoidMethod 的第一个参数必须是 Java 环境,用于运行该方法。 - Evan Leis
如果调用环境是C, 你的说法就是正确的。但由于这里是C++环境,Java环境并不是第一个参数,因为它是消息被调用对象,例如 env->CallVoidMethod(). 从问题中的代码可以看出这里使用的是C++语言。 - mah

0

我想为NoSuchMethodError问题添加另一种解决方案,虽然这里可能不是这种情况,但可能会为您节省很多调试时间。

对于我来说,有一个proguard配置文件需要编辑。否则,所有未在Java代码中调用的非静态Java方法都会被优化掉,而本地C++代码将无法找到它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接