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

咨询:在JNI中无需静态属性实现Android UI更新的可行方案

Android C++ Native代码更新UI(非静态方案)

完全可以不用静态成员,下面是几种可行的实现方式:

1. 直接传入MainActivity实例到Native方法

步骤:

  • 修改Java层的native方法,添加MainActivity类型的参数:
public class MainActivity extends AppCompatActivity {
    private TextView tv;
    // 加载so库
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = findViewById(R.id.sample_text);
        // 调用native方法时传入this
        new Thread(() -> stringFromJNI(MainActivity.this)).start();
    }

    // 更新TextView的方法,非静态
    public void sendMessage(String msg) {
        // 确保在UI线程执行
        runOnUiThread(() -> tv.setText(msg));
    }

    // 修改后的native方法,接收MainActivity实例
    public native void stringFromJNI(MainActivity activity);
}
  • 在C++层通过JNI调用非静态的sendMessage方法:
#include <jni.h>
#include <string>
#include <unistd.h>

extern "C" JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */, jobject activity) {
    // 获取MainActivity的类引用
    jclass cls = env->GetObjectClass(activity);
    // 找到sendMessage方法的ID(参数是String,返回值void)
    jmethodID methodId = env->GetMethodID(cls, "sendMessage", "(Ljava/lang/String;)V");
    if (methodId == nullptr) {
        env->DeleteLocalRef(cls);
        return;
    }

    // 模拟循环更新UI
    for (int i = 0; i < 10; i++) {
        std::string msg = "更新次数: " + std::to_string(i);
        // 把C++字符串转成Java String
        jstring jMsg = env->NewStringUTF(msg.c_str());
        // 调用sendMessage方法
        env->CallVoidMethod(activity, methodId, jMsg);
        // 释放局部引用
        env->DeleteLocalRef(jMsg);
        sleep(1);
    }

    // 释放类引用
    env->DeleteLocalRef(cls);
}

2. 传入Handler实例实现解耦

如果不想直接依赖MainActivity,可以用Handler来传递消息,更灵活:

Java层代码:

public class MainActivity extends AppCompatActivity {
    private TextView tv;
    private Handler uiHandler;

    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = findViewById(R.id.sample_text);

        uiHandler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == 1) {
                    tv.setText((String) msg.obj);
                }
            }
        };

        new Thread(() -> updateUiWithHandler(uiHandler)).start();
    }

    public native void updateUiWithHandler(Handler handler);
}

C++层代码:

#include <jni.h>
#include <string>
#include <unistd.h>

extern "C" JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_updateUiWithHandler(
        JNIEnv* env,
        jobject /* this */, jobject handler) {
    // 获取Handler类
    jclass handlerCls = env->GetObjectClass(handler);
    // 获取sendMessage方法ID(参数是Message,返回值boolean)
    jmethodID sendMsgId = env->GetMethodID(handlerCls, "sendMessage", "(Landroid/os/Message;)Z");
    // 获取Message类
    jclass msgCls = env->FindClass("android/os/Message");
    // 获取Message的obtain静态方法
    jmethodID obtainMsgId = env->GetStaticMethodID(msgCls, "obtain", "()Landroid/os/Message;");
    // 获取Message的what和obj字段ID
    jfieldID whatField = env->GetFieldID(msgCls, "what", "I");
    jfieldID objField = env->GetFieldID(msgCls, "obj", "Ljava/lang/Object;");

    if (!sendMsgId || !obtainMsgId || !whatField || !objField) {
        // 释放引用
        env->DeleteLocalRef(handlerCls);
        env->DeleteLocalRef(msgCls);
        return;
    }

    for (int i = 0; i < 10; i++) {
        // 获取Message实例
        jobject msg = env->CallStaticObjectMethod(msgCls, obtainMsgId);
        // 设置what字段
        env->SetIntField(msg, whatField, 1);
        // 设置消息内容
        std::string content = "Handler更新: " + std::to_string(i);
        jstring jContent = env->NewStringUTF(content.c_str());
        env->SetObjectField(msg, objField, jContent);
        // 发送消息
        env->CallBooleanMethod(handler, sendMsgId, msg);

        // 释放局部引用
        env->DeleteLocalRef(msg);
        env->DeleteLocalRef(jContent);
        sleep(1);
    }

    // 释放类引用
    env->DeleteLocalRef(handlerCls);
    env->DeleteLocalRef(msgCls);
}

关键注意事项

  • UI线程校验:所有更新UI的操作必须在主线程执行,上面两种方案里,第一种用runOnUiThread,第二种用绑定主线程Looper的Handler,都能保证这一点。
  • JNI引用管理:局部引用(比如jobject、jclass)在JNI方法执行完会自动释放,但如果是异步操作(比如native里开了单独线程),需要用NewGlobalRef创建全局引用,用完记得用DeleteGlobalRef释放,避免内存泄漏。
  • 异常处理:JNI调用时要检查methodId、fieldId是否为空,避免崩溃。

内容的提问来源于stack exchange,提问作者david

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 02:45:42