安卓的Handler.post,具体会发生什么?

10

最近几天,我一直试图弄清楚如果在 标签中执行代码会发生什么。

void function(){

  //somePreExecutionCode
  new Handler().post(new Runnable(){
    @Override 
    public void run(){
       //someCode
    }
  });
}

看起来它没有阻塞UI,所以调用函数(buttons)不会卡在点击位置,直到一些代码完成。 但如果一些预执行代码启动进度条,那么进度条将在某些代码完成的正好同一时刻显示。 我知道有AsyncTasks,但还有其他可能性吗?

以及

之间的区别是什么?

new Handler().post 

View.post

?

3个回答

8

创建 Android 应用程序时,系统会创建一个主执行线程。此线程称为 UI 线程,并且所有与 UI 相关的操作都在此线程上进行,以避免同步问题。

在该线程上创建了一个 Looper 实例,其中包含一个 MessageQueue 数据结构。Looper 将处于无限循环状态,等待读取发布在 MessageQueue 上的 Message/Runnable 实例。要将 Message7/Runnable 添加到 MessageQueue 中,需要使用 Handler

创建Handler实例时,它将与当前执行线程和在该特定线程上创建的Looper实例相关联。因此,当您通过Handler发布消息时,消息将添加到MessageQueue中,并由Looper按照FIFO顺序读取,并将传递给目标。new Handler().post()和View.post有所不同。
- 通过View.post发布消息时,可以保证该消息将发布在UI线程的MessageQueue中,因为它内部使用了在UI线程上创建的Handler实例。 - 如果您在UI线程上创建Handler实例并在任何其他线程上使用它发布消息,则该消息将发布到UI线程的MessageQueue中。 - 如果您在非UI线程上创建Handler实例并使用它发布消息,则它们将发布在非UI线程的MessageQueue中。

5
简单来说,有许多线程是Looper threads,其中包括UI thread。这些线程都有自己的Looper,用于运行该线程的消息循环。

通常情况下,这些线程会有一个Handler,用于处理其Looper的消息——重写 public void handleMessage(Message msg) 方法或执行在其looper的消息队列中发布的 Runnable

当你在UI thread上下文中创建一个Handler时(就像你在代码中所做的那样),它会与UI thread的looper关联起来,因此你的\\someCode将在UI thread上运行。

我想,在你的使用场景中,new Handler().post(Runnable)View:post(Runnable)大多数情况下是相同的,因为它们都将一个Runnable添加到UI thread的消息队列中。

但它们并不完全相同。

  • View:post(Runnable)会将一个Runnable添加到UI thread的looper消息队列中;
  • Handler:post(Runnable)会将一个Runnable添加到与其关联的线程looper的消息队列中。

我的解释基本上是直观的,因此如果我有错误,请指出。


1
根据Android View的文档

Runnable将在用户界面线程上运行

根据Android Handler的文档

Runnable将在此处理程序附加的线程上运行

因此,在Handler的情况下,您可以在任何想要的线程中创建它,它是一种锚点,将在它创建的线程中执行提供的Runnable。
在View.post中,您将始终在UI线程中执行Runnable。

我还要补充的是,如果要在线程中使用Handler,则必须先通过调用Looper.prepare()方法来关联一个Looper,然后再创建Handler,最后在初始化处理程序后调用Looper.loop()方法。 - Drew
1
我经常使用Handlers,但我从未使用过Loopers... 什么时候必须使用Loopers?编辑:算了吧,我刚刚看到你的答案。不错,解释得很好。 - Jeje Doudou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接