我可以在 UI 线程的密集任务期间更新 UI 一个 "tick" 吗?

Can I update the UI one "tick" during intensive task on the UI thread?

我的应用程序有一个密集型任务,我目前 运行正在 UI 线程上。大约需要 15 秒。因此,我确实需要在任务期间的战略点更新 UI,以免用户(和 OS)认为应用程序已崩溃(停止响应)。

似乎可以做这样的事情(伪代码):

void longTaskOnUIThread() {
    // Here I'm maintaining the sequence of steps as a sequence of statements
    // in one method, despite letting the UI catch its breath between steps.
    doAChunkOfTheTask();
    dispatchUIQueueMessage();
    int result = doSecondChunkOfTheTask();
    if (result < 3) {
        dispatchUIQueueMessage();
        doThirdChunkOfTheTask();
    }
}

void dispatchUIQueueMessage() {
    // Give the UI a chance to catch up a little:
    final MessageQueue queue = Looper.getMainLooper().mQueue; // not public
    // Don't block if no messages are ready.
    if (queue.hasMessages(...)) {
        Message msg = queue.next(); // Isn't public. :-(
        msg.target.dispatchMessage(msg);
    }
}

我基于 Looper source code,但我不想使用未记录的功能,因为我无法依赖它们。如果有looper.dispatchNextMessageIfAny()方法就好了

不重复:Android - updating UI during intensive task? 类似,但那个是关于从 工作线程 更新 UI。这种方法在这里行不通,因为只有 UI 线程可以更新 UI,而 UI 线程一直在忙于它的密集任务……除非它明确地需要一点时间允许发送消息。

我意识到 推荐的方法是 运行 后台线程上的密集任务, 这应该让 UI 线程自由更新UI 在需要的时候。这就是我通常做的,例如使用新的 AsyncTasks 和单独的服务。但这需要更多的控制流复杂性(编排),在每个任务完成后将控制传回,并跟踪状态以确定哪个异步任务跟随哪个。

这个问题是为了调查有哪些选项可用 来在 UI 线程上执行操作,同时允许 UI 有时更新。了解选项是什么将有助于确定在某些情况下是否可以在 UI 线程上执行操作。如果结论是否定的,那么这个问题的答案将帮助我知道为什么我可以自信地将我的时间投入到另一个方向。

My app has an intensive task that I'm currently running on the UI thread

如名称所示 UI 线程用于 UI。如果你在那个线程上做繁重的工作,那么你肯定做错了。

But that requires more control flow complexity (orchestration),

没有。它只需要与使用 AsyncTask 所做的工作量相同。或者你可以使用 RxJava。或者只是简单的 EventBus。它并不比平常复杂。

passing control back after each task completes

为什么首先将控制权交给计算线程?控件应始终保持在 UI 线程上。

您可以使用 runOnUiThread 方法:

    SomeActivity.this.runOnUiThread(new Runnable() {
        public void run() {

            //update your ui here
        }
    });

您可以从工作线程调用它

从这里的答案和我所做的研究来看,答案似乎是,你不能,在 UI 线程,告诉 UI 到 "update a little bit" 而不放弃控制流(即让 UI 更新而不从正在执行的方法返回)。

这有助于我更有信心地做出决定,我需要将控制流/编排移到一个更大的服务任务中,而不是让 UI 线程在几个较小的服务任务之间编排。