You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:46:07