Handler 简介:
主要作用:1>在新起的线程中发送消息
2>在主线程中(UI线程,main thread)中接收消息,并更新UI。
原因:Android4.0后,Google官方禁止在主线程中进行耗时操作,避免引起ANR,提高用户体验。假设不用Handler的话,改用加锁方案,但是稍微一想就会发现,这样的方式会无限增加代码的复杂度,增加代码的耦合,而且锁问题还会引起别的不稳定因素。
用法:
构建Handler的成员变量,重写handleMessage(android.os.Message msg)方法,开启子线程或在回调中发送消息方法一般有:sendEmptyMessage或者obtainMessage,这两者的区别主要在与obtainMessage可以避免创建对象,从而减少内存的开销。
Handler中一共涉及到四个对象:Handler、Message、Looper、MessageQueue。这四者的关系和原理:
Message:Handler发送、接受和处理的消息对象;
Looper:每个线程都有一个Looper对象,负责无限循环的去从消息队列中取消息,并将读取到的消息发送给Handler对象去处理;
MessageQueue:消息队列,它采用先进先出的方式去管理Message,程序在创建Looper对象时,会在他的构造器中创建MessageQueue,源码:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Handler:作用有两个,发送消息和处理消息,Handler发送的消息必须送到指定的MessageQueue,而MessageQueue是由Looper负责管理的,因此要想Handler正常工作,必须在当前线程中有一个Looper对象这里分为两种情况:
1>主线程(UI线程),系统已经初始化了一个Looper对象,因此程序直接创建Handler即可
2>程序员自己创建的子线程,这时,程序员必须创建一个Looper对象,并启动它。
创建Looper使用:Looper.prepare(),查看源码:
1 public static void prepare() {
2 prepare(true);
3 }
4
5 private static void prepare(boolean quitAllowed) {
6 if (sThreadLocal.get() != null) {
7 throw new RuntimeException("Only one Looper may be created per thread");
8 }
9 sThreadLocal.set(new Looper(quitAllowed));
10 }
11
12 private Looper(boolean quitAllowed) {
13 mQueue = new MessageQueue(quitAllowed);
14 mThread = Thread.currentThread();
15 }
通过方法调用,第9行创建Looper对象,创建Looper对象时同时会创建MessageQueue对象(第13行)。此外,可以看出prepare()允许一个线程最多有一个Looper被创建。
然后调用Looper的looper()方法来启动它,looper()使用一个死循环不断取出MessageQueue中的消息,并将消息发送给对应的Handler进行处理。下面是Looper类中looper()方法的部分源码:
1 for (;;) {
2 Message msg = queue.next(); // might block
3 if (msg == null) {
4 // No message indicates that the message queue is
quitting.
5 return;
6 }
7
8 // This must be in a local variable, in case a UI event sets the logger
9 Printer logging = me.mLogging;
10 if (logging != null) {
11 logging.println(">>>>> Dispatching to " + msg.target + " " +
12 msg.callback + ": " + msg.what);
13 }
14
15 msg.target.dispatchMessage(msg);
16
17 if (logging != null) {
18 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
19 }
20
21 // Make sure that during the course of dispatching the
22 // identity of the thread wasn't corrupted.
23 final long newIdent = Binder.clearCallingIdentity();
24 if (ident != newIdent) {
25 Log.wtf(TAG, "Thread identity changed from 0x"
26 + Long.toHexString(ident) + " to 0x"
27 + Long.toHexString(newIdent) + " while dispatching to "
28 + msg.target.getClass().getName() + " "
29 + msg.callback + " what=" + msg.what);
30 }
31
32 msg.recycleUnchecked();
33 }
很明显第1行用了一个死循环,第2行从queue中取出Message,第15行通过dispatchMessage(Message msg)方法将消息发送给Handler。