一. 概述:Handler、消息队列和Looper
Handler
的功能:将一个任务切换到某个指定的线程中去执行。- UI线程:
Handler
常见于从工作线程切换到UI线程。因为Android UI使用的是单线程模式,不允许在其它子线程中访问UI。如果在多线程中并发访问UI,可能导致UI控件处于不可控的状态,它不是线程安全的。 工作流程:
- Thread2中创建Handler对象,Handler内部维护一个Looper和消息队列。
- 在Thread1中对该Handler对象发送消息。
- Looper不断循环从消息队列中取出消息来处理
- 此时Handler的
handleMessage
是运行在Thread2中。哪个线程创建了Handler对象,那么最终处理消息时的工作就已经切换到该线程中。
二. 消息机制分析
ThreadLocal
机制:
- 当一个变量以线程为作用域,而且每个线程都需要拥有独立的变量副本时,就适合使用
ThreadLocal
。 - 具体到Androd,对于Handler来说,Looper的作用域就是线程,而且每个线程都拥有独立的Looper。此时使用
ThreadLocal
就非常合适。 - 其它的用途场景:每个线程都需要一个独立的监听器对象时。
- 关于
ThreadLocal
,我单独再开一篇来阐述。
- 当一个变量以线程为作用域,而且每个线程都需要拥有独立的变量副本时,就适合使用
消息队列(
MessageQueue
)的工作原理:enqueueMessage
方法: 插入一条消息进入队列。next
方法:取出一条消息,并从队列移出。这是个无限循环的方法,如果队列中没有消息,就会一直阻塞。当有新消息到来时,next方法会返回这条消息,并将其从单链表中移出。
Looper
工作原理:创建:
new Thread(){ public void run() { Looper.prepare(); Handler handler = new Handler(); Looper.loop(); } }.start();
- 退出Looper:
quit
和quitSafely
方法。其中quitSafely
并不立刻退出,而是等队列中已有的消息处理完毕后才会退出。
- 退出Looper后,Handler的send会返回false,消息发送将会失败。
- 在子线程中,如果手动创建了Looper,应当在所有事情完成后,调用quit方法来终止循环,否则这个子线程将一直处于等待状态。
- 调用loop方法后,消息循环系统才会开始工作。
- loop方法是一个死循环,只有当quit或quitSafely调用时,才会退出循环。
- Handler的工作原理
- 发送消息:向消息队列中插入一条消息,MessageQueue的next方法就会返回这条消息给Looper,接着Looper就会处理这条消息,但最终,Looper会将这条消息交由Handler来处理,
dispatchMessage
方法会被调用,Handler进入处理消息的阶段。 - 处理消息:
- 检查Message的callback(一个Runnable对象)是否为null,不为null就通过
handleCallback
来处理消息。 - 检查mCallback是否为null,不为null就调用
handleMessage
来处理消息。你可以通过Handler的构造方法传入一个Callback,这样就无需派生一个Handler的子类了。 - 最后调用Handler的
handleMessage
方法来处理消息。
- 检查Message的callback(一个Runnable对象)是否为null,不为null就通过
- 你也可以手动创建Looper来构造Handler。
- 发送消息:向消息队列中插入一条消息,MessageQueue的next方法就会返回这条消息给Looper,接着Looper就会处理这条消息,但最终,Looper会将这条消息交由Handler来处理,
三. 主线程的消息循环
Android的主线程就是
ActivityThread
,入口方法为main
,在main
方法中系统会通过Looper.prepareMainLooper()
来创建主线程的Looper和MessageQueue,并调用loop
开启循环。ActivityThread.H
: 主线程的Handler。- 它通过
ApplicationThread
和AMS远程通信。AMS在以IPC方式完成ActivityThread
的请求后,会回调ApplicationThread
的Binder
方法,然后ApplicationThread
会给H发送消息。 - H收到消息后,会将
ApplicationThread
中的逻辑切换到ActivityThread
中执行,即切换到主线程中去执行。
- 它通过