简答:它们都在同一个线程上运行。如果从 Activity 生命周期回调实例化,它们都在主 UI 线程上运行。
长答案:
一个线程可能有一个Looper,其中包含一个MessageQueue。为了使用这个功能,你必须在当前线程上创建一个Looper,通过调用(静态)Looper.prepare(),然后通过调用(也是静态的)Looper.loop() 开始循环。这些是静态的,因为每个线程应该只有一个 Looper。
对loop() 的调用通常在一段时间内不会返回,但会不断从MessageQueue 中获取消息(“任务”、“命令”或您喜欢的任何名称)并单独处理它们(例如,通过回调消息中包含的Runnable)。当队列中没有消息时,线程会阻塞,直到有新消息。要停止Looper,您必须对其调用quit()(这可能不会立即停止循环,而是设置一个从循环中定期检查的私有标志,指示它停止)。
但是,您不能直接将消息添加到队列中。相反,您注册一个MessageQueue.IdleHandler 以等待queueIdle() 回调,您可以在其中决定是否要执行某些操作。依次调用所有处理程序。 (所以“队列”并不是真正的队列,而是定期调用的回调集合。)
关于上一段的注意事项:我实际上猜到了。我找不到任何关于此的文档,但这是有道理的。
更新:见ahcox' comment和his answer。
因为工作量很大,所以框架提供了Handler 类来简化事情。当您创建Handler 实例时,它(默认情况下)绑定到已附加到当前线程的Looper。 (Handler 知道要附加到什么Looper,因为我们之前调用了prepare(),它可能在ThreadLocal 中存储了对Looper 的引用。)
使用 Handler,您只需调用 post() 即可“将消息放入线程的消息队列”(可以这么说)。 Handler 将处理所有 IdleHandler 回调的内容,并确保您发布的 Runnable 被执行。 (如果您延迟发布,它也可能会检查时间是否正确。)
明确一点:真正使循环线程做某事的唯一方法是向其循环发布消息。这在您调用 looper 上的 quit() 之前有效。
关于 android UI 线程: 在某个时间点(可能在创建任何活动等之前)框架设置了一个Looper(包含一个MessageQueue)并启动它。从这一点开始,UI 线程上发生的一切都通过该循环。这包括活动生命周期管理等。您覆盖的所有回调(onCreate()、onDestroy()...)至少是从该循环中间接分派的。例如,您可以在异常的堆栈跟踪中看到这一点。 (你可以试试,在onCreate()的某处写int a = 1 / 0;...)
我希望这是有道理的。抱歉之前不清楚。