我的目标是在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");
}
}
在此精简版本中,我希望文本框继续显示相同的字符串,因为每个string
都会传递相同的callback
。相反,app
是crashing
。堆栈跟踪显示以下错误
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()>
答案 0 :(得分:-1)
我找到了可行的解决方案。下面是功能性的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;
}