Android Native Activity中C++调用Java方法崩溃问题求助
NativeActivity中JNI调用CallVoidMethod崩溃的解决方案
你遇到的问题核心是误用了NativeActivity的类对象而非实例对象,导致JNI调用时崩溃。咱们一步步拆解问题和解决办法:
问题根源
在android_main传入的struct android_app中:
main_activity->clazz是NativeActivity的类对象(jclass),代表的是类本身,不是具体的Activity实例;- 而调用非静态Java方法(比如你的
SendNotification)必须传入实例对象(jobject),你把类对象传给CallVoidMethod,自然会引发崩溃。
普通Activity中你应该是持有了Activity的实例引用,所以没问题,但NativeActivity的结构体字段容易混淆,这是JNI开发里的常见坑。
修正后的Native代码
首先把类对象换成实例对象,同时增加错误检查避免潜在问题:
void SendNotification() { JavaVM* lJavaVM = main_activity->vm; JNIEnv* lJNIEnv = main_activity->env; JavaVMAttachArgs lJavaVMAttachArgs; lJavaVMAttachArgs.version = JNI_VERSION_1_6; lJavaVMAttachArgs.name = "NativeThread"; lJavaVMAttachArgs.group = NULL; jint lResult = lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs); if (lResult == JNI_ERR) { // 可添加日志输出 Attach失败信息 return; } // 关键:使用activity字段,这才是当前NativeActivity的实例对象 jobject activityInstance = main_activity->activity; if (activityInstance == nullptr) { lJavaVM->DetachCurrentThread(); return; } // 获取你的MainActivity类对象(因为你的Activity是NativeActivity的子类) jclass mainActivityClass = lJNIEnv->GetObjectClass(activityInstance); if (mainActivityClass == nullptr) { lJavaVM->DetachCurrentThread(); return; } // 获取目标方法ID,签名要严格匹配 jmethodID sendNotificationMethod = lJNIEnv->GetMethodID(mainActivityClass, "SendNotification", "()V"); if (sendNotificationMethod != nullptr) { lJNIEnv->CallVoidMethod(activityInstance, sendNotificationMethod); // 检查JNI调用是否产生异常 if (lJNIEnv->ExceptionCheck()) { lJNIEnv->ExceptionClear(); // 这里可以加日志记录异常信息 } } // 注意:如果当前线程原本就是Java线程,Detach会出问题,建议根据实际场景判断是否需要Detach lJavaVM->DetachCurrentThread(); }
额外注意:UI操作必须在主线程执行
你的SendNotification方法里创建了AlertDialog,这是UI操作,必须在Android主线程执行。如果你的Native代码是在子线程调用SendNotification,即使修正了实例对象,还是会崩溃!
解决办法是在Java层确保代码运行在主线程,比如添加Handler:
package com.thor.kalen; import android.app.AlertDialog; import android.app.NativeActivity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; public class MainActivity extends NativeActivity { private Handler mainThreadHandler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 初始化主线程Handler mainThreadHandler = new Handler(Looper.getMainLooper()); } public void SendNotification() { // 把UI操作投递到主线程执行 mainThreadHandler.post(() -> { new AlertDialog.Builder(this) .setTitle("Alert") .setMessage("Notification from Native Code!") .setNeutralButton("Close", null) .show(); }); } }
总结几个关键要点
- 区分JNI中的
jclass(类)和jobject(实例),调用非静态方法必须传实例; - NativeActivity的
android_app->activity才是当前Activity的实例,clazz是类对象; - Android所有UI操作必须在主线程执行,务必确保你的Java方法运行在主线程;
- 增加JNI调用的错误检查(比如空指针、异常),方便快速定位问题。
内容的提问来源于stack exchange,提问作者Skrakle
相关产品推荐
相关产品推荐

