【问题标题】:What is the meaning of : "Events are received on the UI thread and read on the main loop thread"?什么意思:“在 UI 线程上接收事件并在主循环线程上读取”?
【发布时间】:2020-06-01 18:07:34
【问题描述】:

最近我一直在通过《开始 Android 游戏》一书进行 Android 开发。它包含以下代码:

public class KeyboardHandler implements OnKeyListener {
    boolean[] pressedKeys = new boolean[128];
    Pool<KeyEvent> keyEventPool;
    List<KeyEvent> keyEventsBuffer = new ArrayList<KeyEvent>();
    List<KeyEvent> keyEvents = new ArrayList<KeyEvent>();
    public KeyboardHandler(View view) {
        PoolObjectFactory<KeyEvent> factory = new PoolObjectFactory<KeyEvent>() {
            public KeyEvent createObject() {
                return new KeyEvent();
            }
        };
        keyEventPool = new Pool<KeyEvent>(factory, 100);
        view.setOnKeyListener(this);
        view.setFocusableInTouchMode(true);
        view.requestFocus();
    }
    public boolean onKey(View v, int keyCode, android.view.KeyEvent event) {
        if (event.getAction() == android.view.KeyEvent.ACTION_MULTIPLE)
            return false;

        synchronized (this) {
            KeyEvent keyEvent = keyEventPool.newObject();
            keyEvent.keyCode = keyCode;
            keyEvent.keyChar = (char) event.getUnicodeChar();
            if (event.getAction() == android.view.KeyEvent.ACTION_DOWN) {
                keyEvent.type = KeyEvent.KEY_DOWN;
                if(keyCode > 0 && keyCode < 127)
                    pressedKeys[keyCode] = true;
            }
            if (event.getAction() == android.view.KeyEvent.ACTION_UP) {
                keyEvent.type = KeyEvent.KEY_UP;
                if(keyCode > 0 && keyCode < 127)
                    pressedKeys[keyCode] = false;
            }
            keyEventsBuffer.add(keyEvent);
        }
        return false;
    }

我又一次有点困惑为什么synchronized 是必要的,这本书说: “记住 事件在 UI 线程上接收并在主循环线程上读取,所以我们 必须确保我们的成员都不会被并行访问。 " 首先,我认为UI线程与主线程相同(或主循环线程,有区别吗?)说UI线程正在执行这段代码,因此也接收事件(因为这个类实现了OnClickListener)。假设主循环 while(!userquit) 循环在单独的线程上运行。主循环线程如何读取事件?另外,主循环不应该在 UI 线程上运行吗?我对事件处理的看法正确吗?当 keyEvent 发生时,执行 KeyboardHandler 的线程会执行代码 onKey()。如何在 UI 线程上接收事件,但在 Main Loop 线程上读取?事件不应该在同一个线程上接收和处理吗?

【问题讨论】:

    标签: java android multithreading


    【解决方案1】:

    在 Android 中,您无法在主线程之外访问用户界面组件。它可以防止多线程的各种错误。要访问 UI 组件,无论哪种方式,您都可以使用 context.runOnUiThread 方法,该方法允许您在 UI 线程上运行命令,正如其名称所暗示的那样。

    另一种方法是使用synchronized 关键字,正如this answer 中所述,它允许两个线程相互读写。这样,synchronized 关键字允许非 UI 线程仍然与 UI 组件交互。

    【讨论】:

    • 什么是 UI 组件? OnKeyListner 是 UI 组件吗?
    • 是的,onKey,更具体地说,是同步块中的所有操作。
    【解决方案2】:

    你是正确的主线程和ui线程是同义词并且是同一个线程。

    您可以像这样轻松地确认这一点:

    getActivity().runOnUiThread(() -> {
       Log.d(TAG, "runOnUiThread is run by main looper: "+Looper.getMainLooper().isCurrentThread());
    });
    

    将输出:

    runOnUiThread is run by main looper: true
    

    所以文档的声明

    在 UI 线程上接收事件并在主循环线程上读取

    是错误的或至少是误导性的。

    更好的措辞是

    在 UI 线程上接收事件并由主循环器执行 就可以了。

    他们最可能想要传达的是,您的应用程序的其余部分不是(或不应该)在 UI 线程上运行,而是在操作相同的数据。因此,当您突然在不同的线程(UI 线程)上操作相同的数据时,可能需要进行同步。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-24
      • 1970-01-01
      • 2021-03-06
      • 1970-01-01
      • 1970-01-01
      • 2021-01-03
      • 2021-04-18
      相关资源
      最近更新 更多