说说Handler的工作原理

单线程模型

我们知道,Android系统是单线程模型,即应用程序启动时,系统会创建一个主线程,又叫做UI线程,负责与UI组件(进行交互,比如控制UI界面界面显示、更新等,UI线程只能处理一些简单的、短暂的操作,如果要执行繁重的任务或者耗时很长的操作,比如访问网络、数据库、下载等,这种单线程模型会导致线程运行性能大大降低,甚至阻塞UI线程,如果被阻塞超过5秒,系统会提示应用程序无相应对话框,即ANR,导致退出整个应用程序或者短暂杀死应用程序,所以Android系统将大部分耗时、繁重任务交给子线程完成,不会在主线程中完成;同时,Android只允许主线程更新UI界面,子线程处理后的结果无法和主线程交互,即无法直接访问主线程,这就要用到Handler机制来解决此问题

Handler

在我们在子线程中执行完耗时操作后很多情况下我们需要更新UI,但我们都知道,不能在子线程中更新UI。此时最常用的手段就是通过Handler将一个Message消息send到UI线程中,然后再在Handler的handleMessage方法中进行处理,常见代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private Handler mHandle = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case xx:
break;
}
}
};
new Thread() {
@Override
public void run() {
super.run();
//耗时操作
Message msg = new Message();
msg.what = WHAT;
mHandle.sendMessage(msg);
}
}.start();

每个Handler都会关联一个消息队列,消息队列被封装在Lopper中,而每个Looper又会关联一个线程(ThreadLocal),也就是每个消息队列会关联一个线程。Handler就是一个消息处理器,将消息投递给消息队列,然后再由对应的线程从消息队列中挨个取出消息,并且执行。默认情况下,消息队列只有一个,即主线程的消息队列,这个消息队列是在系统的启动过程中的ActivityThread.main方法中创建的,通过Lopper.prepareMainLooper()来创建,然后最后执行Looper.loop()来启动消息循环。那么我们为什么在平时的使用Handler的时候,并没有使用Looper呀,其实是因为系统为我们创建好了,我们可以查看ActivityThread.java来看看这个过程,只列了关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public final class ActivityThread {
...
public static final void main(String[] args) {
...
Looper.prepareMainLooper();// 1、创建消息循环Looper
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler(); // 主线程的Handler
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();// 2、执行消息循环
if (Process.supportsProcesses()) {
throw new RuntimeException("Main thread loop unexpectedly exited");
}
thread.detach();
...
}
...
}

通过上面的原理介绍,我们可以画出下面这个流程图

那么它们具体是怎么协作的呢?下面我们通过源码一步步解析,首先看下Handler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper(); // 获取Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; // 获取消息队列
mCallback = null;
}

从Handler默认的构造函数中我们可以看到,Handler会在内部通过Looper.getLooper()来获取Looper对象,并且与之关联,那么Looper.myLooper又是如何工作的呢?我们继续往下看.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
myLooper().mQueue.mQuitAllowed = false;
}
private synchronized static void setMainLooper(Looper looper) {
mMainLooper = looper;
}
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}

我们看到myLooper()方法是通过sThreadLocal.get()来获取的,上面也提到,在ActivityThread.main方法中会调用prepareMainLooper()方法,prepareMainLooper中执行了prepareprepare中会创建一个Looper并赋值给 sThreadLocal,这样Looper就和线程关联上了,而且有一点很重要,普通的线程是没有looper的,如果需要looper对象,那么必须要先调用Looper.prepare()方法,而且一个线程只能有一个looper ,而在Handler中,消息队列通过Looper与线程关联,而Handler又与Looper关联,因此Handler最终就和线程、线程的消息队列关联上了,那么创建了Looper后,是如何执行消息循环呢?我们来看下Looper.loop()方法

Looper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public static void loop() {
final Looper me = myLooper();//获取looper对象
if (me == null) {
//若为空则说明当前线程不是LooperThread,抛出异常
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; 获取消息队列
.....
for (;;) {
//死循环不断取出消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
//打印log,说明开始处理message。msg.target就是Handler对象
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
//开始处理message,msg.target就是Handler对象
msg.target.dispatchMessage(msg);
.....
}
}

很明显,就是一个大的循环,不断从消息队列出取出消息。然后调用一个很关键的方法msg.target.dispatchMessage(msg)开始处理消息。msg.target就是message对应的handler,所以对于Looper,我们结论就是通过Looper.prepare()来创建Looper对象(消息队列封装在Looper对象中),并且保存在sThreadLoal中,然后通过Looper.loop()来执行消息循环,这两步通常是成对出现的!

Message

最后我们看看消息处理机制,先看看Message

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public final class Message implements Parcelable {
public int what;
public int arg1;
public int arg2;
public Object obj;
int flags;
long when;
Bundle data;
Handler target; // target处理
Runnable callback; // Runnable类型的callback
// sometimes we store linked lists of these things
Message next; // 下一条消息,消息队列是链式存储的
....
}

前面说到loop循环中处理信息的msg.target.dispatchMessage(msg)方法。现在我们来看下这个方法的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void dispatchMessage(Message msg) {
//注意!这里先判断message的callback是否为空,否则就直接处理message的回调函数
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
//正是在这调用我们平常重写handleMessage
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}

这里为什么要先判断msg.callback!=null呢,因为post(Runnable r)方法也能用来处理事件

1
2
3
4
5
6
7
8
9
10
public final boolean post(Runnable r){
//获取消息并发送给消息队列
return sendMessageDelayed(getPostMessage(r), 0);
}
private final Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}

在post(Runnable r)时,会将Runnable包装成Message对象,并且将Runnable对象设置给Message对象的callback字段,最后会将该Message对象插入消息队列。

至此,Handler的工作原理就说完了。