使用 C++ 中的 NDK 更新 Android UI

2023-12-11

我的问题与这篇文章直接相关:https://groups.google.com/forum/#!topic/android-ndk/291sBdkITyI

基本上,我有一个用 C++ 编写的应用程序,使用 NDK 编译,具有基本的 Android(活动)。我有一个文本视图(Java 中),当 C++ 端发生某些情况(例如状态更改)时,需要更新该文本视图。我想从 C++ 调用 Java 并在状态更改时更新文本视图。

在上面的链接中,他们使用的代码是(可能是伪代码):

public class Example extends Activity{    

    Handler handler = new Handler() {

         @Override
         public void handleMessage(Message msg) {
             this.currentDownloadField.setText(""+ msg.what);
         }

    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // whatever
    }   

    public static void sendMessage(int  id){ 
         handler.sendEmptyMessage(id); // just the what() is filled with the id
    }
}

从 C++ 调用将是

void sendMessage(char* buffer, int bufferlen) {
    JNIEnv *env = NULL;
    jmethodID mid = NULL;
    jbyteArray message;

    jint res = (jjvm->AttachCurrentThread(&jjvm, &env, NULL));

    if (res >= 0) {
        message = (*env)->NewByteArray(env, bufferlen);
        (*env)->SetByteArrayRegion(env, message, 0, bufferlen, (const jbyte *) ((BYTE*) buffer));
        mid = (*env)->GetStaticMethodID(env, jcls, "sendMessage", "([B)V");

        // Mid <= 0 ? Not found : OK
        if (mid > 0) {
        (*env)->CallStaticVoidMethod(env, jcls, mid, message);
        }
    }
}

问题是在静态函数的活动中使用“处理程序”不起作用(因为它不是静态的)。如果它是静态的,那么如何引用“this.currentDownloadField”?

我也尝试过从 C++ 调用公共函数

public void update(String message) {
    Log.i("logging", "Hit here")
    mMyTextField.setText(message);
}

当 C++ 调用 Java 函数“更新”时,日志命中(在 logcat 中),但文本视图不会更新。也许这是线程的问题,但我不知道如何正确更新文本字段。

另一种选择是轮询并让 Java 调用 C++ 来读取变量(状态),但这很乏味并且不是良好的编程实践。

有什么建议来解决这个问题吗?

提前致谢。


你说得对,你必须打电话mMyTextField.setText()来自 UI 线程。 Android Java 类提供了多种方法来做到这一点,例如查看.post() or 处理程序.post() or Handler.sendMessage(), or Activity.runOnUiThread()。这些方法都不是static,他们都需要活下去this反对工作。

有不同的方法可以根据您的目的解决此问题。可能对代码的最小更改如下:

public class Example extends Activity {

    private static Handler staticHandler;
    private TextView currentDownloadField;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                this.currentDownloadField.setText(""+ msg.what);
            }
        }
        staticHandler = handler;
        setContentView(R.layout.main_view);
        currentDownloadField = (TextView)findViewById(R.id.download_field);
    }

    @Override
    protected void onDestroy() {
        staticHandler = null;
    }

    public static void sendMessage(int id) {
        staticHandler.sendEmptyMessage(id); // just the what() is filled with the id
    }
}

在上面的代码中,为了简洁起见,跳过了错误检查。

或者,您可以将对 Activity(或处理程序或 downloadFiled)的引用传递给 C 库,而不是调用CallStaticVoidMethod()您将使用对象全局引用并使用CallVoidMethod(env, jactivityObj, mid, message).

PS我只是想知道,如果您发送一个jbyteArray(在Java中,那就是byte[]) 到期望的回调方法int?

Update上面的简单代码受处理程序泄漏,因此如果您想在生产中重用它,请包含处理程序周围的静态内部类包装器.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 C++ 中的 NDK 更新 Android UI 的相关文章

随机推荐