java - JNI 错误 - 使用 CallVoidMethod 时无法调用 [方法]

标签 java android c callback java-native-interface

我的目标是在 C 代码中建立一个无限循环,执行将 String 传递给 Java 函数的回调。然后,Java 函数使用String 来更新文本框的内容。问题是回调尝试生成以下错误:

JNI DETECTED ERROR IN APPLICATION: can't call void com.example.helloneon.HelloNeon.updateSign(java.lang.String) on instance of java.lang.Class<com.example.helloneon.HelloNeon>

C 代码:

/* return current time in milliseconds */
static double
now_ms(void)
{
    struct timespec res;
    clock_gettime(CLOCK_REALTIME, &res);
    return 1000.0*res.tv_sec + (double)res.tv_nsec/1e6;
}
jstring  Java_com_example_helloneon_HelloNeon_stringFromJNI( JNIEnv* env,
                                                    jobject thiz ) {
    int seconsaperline = 3;
    static double t0 = 0;
    if (t0 == 0) { t0 = now_ms(); }
    //jclass cls = (*env)->FindClass(env, "com/example/helloneon/HelloNeon");
    jclass cls = (*env)->GetObjectClass(env,thiz) ;

    jmethodID timerId2 = (*env)->GetMethodID(env, cls,
                                             "updateSign", "(Ljava/lang/String;)V");
    jstring jstr = (*env)->NewStringUTF(env, "line nnnn");

    while (true) {
        if (((now_ms() - t0) * .001) >= seconsaperline) {
            t0 = now_ms();
        }
        //generates:
        // JNI DETECTED ERROR IN APPLICATION: can't call void com.example.helloneon.HelloNeon.updateSign(java.lang.String) on instance of java.lang.Class<com.example.helloneon.HelloNeon>
        (*env)->CallVoidMethod(env, cls, timerId2, jstr);
    }
    //return jstr;

}

java代码:

public class HelloNeon extends AppCompatActivity {

    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hello_neon);

        tv = findViewById(R.id.text_view_hello_neon);
        /*
        ((TextView)findViewById(R.id.text_view_hello_neon))
                .setText(stringFromJNI());  */

        new doWork().execute("");
    }


    /*called from c code*/
    @Keep
    public  void updateSign(final String  line) {

        runOnUiThread(new Runnable() {
            @Override
            public void run() {

                HelloNeon.this.tv.setText(line);
            }
        });

    }
    public native String stringFromJNI();



    public class doWork extends AsyncTask<String, Void, String[]> {

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected String[] doInBackground(String... params) {


            while (true) {

                stringFromJNI();

            }


            // return null;

        }

        @Override
        protected void onPostExecute(String[] passedData) {
        }

    }

    static {
        System.loadLibrary("hello-neon");
    }
}

在此精简版本中,我希望文本框继续显示相同的字符串,因为每个回调都会传递相同的字符串。相反,应用程序正在崩溃。堆栈跟踪给出以下错误

2019-09-05 20:42:10.330 8764-8791/com.example.helloneon A/ample.helloneo: runtime.cc:566] JNI DETECTED ERROR IN APPLICATION: can't call void com.example.helloneon.HelloNeon.updateSign(java.lang.String) on instance of java.lang.Class<com.example.helloneon.HelloNeon>
2019-09-05 20:42:10.330 8764-8791/com.example.helloneon A/ample.helloneo: runtime.cc:566]     in call to CallVoidMethod
2019-09-05 20:42:10.330 8764-8791/com.example.helloneon A/ample.helloneo: runtime.cc:566]     from java.lang.String com.example.helloneon.HelloNeon.stringFromJNI()

编辑: 根据我替换的 C 代码中的建议

jmethodID timerId2 = (*env)->GetMethodID(env, cls,
                                                 "updateSign", "(Ljava/lang/String;)V");

jmethodID timerId2 = (*env)->GetMethodID(env, thiz,
                                                 "updateSign", "(Ljava/lang/String;)V");

然后用

jmethodID timerId2 = (*env)->GetMethodID(env, (jclass) thiz,
                                             "updateSign", "(Ljava/lang/String;)V");

这两项更改都产生了以下错误

JNI 在应用程序中检测到错误:jclass 的类型错误:com.example.helloneon.HelloNeon 2019-09-06 17:31:42.752 9787-9826/com.example.helloneon A/ample.helloneo:runtime.cc:566] 调用 GetMethodID 2019-09-06 17:31:42.752 9787-9826/com.example.helloneon A/ample.helloneo:runtime.cc:566] 来自 java.lang.String com.example.helloneon.HelloNeon.stringFromJNI()

最佳答案

我找到了一个有效的解决方案。下面是函数式c代码

jstring  Java_com_example_helloneon_HelloNeon_stringFromJNI( JNIEnv* env,
                                                             jobject thiz ) {

    int seconsaperline = 3;
    static double t0 = 0;
    if (t0 == 0) { t0 = now_ms(); }

    //originally incorrectly used just this in place of next 2
    jclass clz = (*env)->GetObjectClass(env, thiz);

    //fix added following line, passing jniHelperClz to GetMethodID:
    jclass jniHelperClz = (*env)->NewGlobalRef(env, clz);

    //fix added following line, passing mainActivityObj to CallVoidMethod:
    jclass mainActivityObj = (*env)->NewGlobalRef(env, thiz);

    jmethodID timerId2 = (*env)->GetMethodID(env, jniHelperClz,
                                             "updateSign", "(Ljava/lang/String;)V");


    jstring jstr = (*env)->NewStringUTF(env, "line nnnn");
    while (true) {
        if (((now_ms() - t0) * .001) >= seconsaperline) {
            t0 = now_ms();
        }

         (*env)->CallVoidMethod(env, mainActivityObj, timerId2, jstr);
    }
    //return jstr;

}

关于java - JNI 错误 - 使用 CallVoidMethod 时无法调用 [方法],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57814634/

相关文章:

c - 将链表实现与 malloc 函数分离

java - 扫描条形码时出错 Mobile Vision API?

java - Camel 延迟会覆盖任何重新投递策略

java - 错误: cannot find symbol while calling toString method

java - 可以使用静态 "database helper"类吗?

android - 如何自动将APK从手机推送到Wear?

java - 面临主要 Activity 困难

c++ - 结构中的结构数组 - 指针类型是什么?

java为另一个接口(interface)创建一个包装接口(interface)

c - 打开文件的段错误多线程