Handler是处理线程与线程之前通信的一套机制。Handler是常被开发者拿来更新UI的一种消息处理机制,它的运行机制需要底层的Looper和MessageQueue的支撑。
一、创建Handler
在子线程中通过new Handler()创建的Handler是会导致程序崩溃的,提示的错误信息为 Can't create handler inside thread that has not called Looper.prepare() 。意思是不能在没有调用Looper.prepare() 的线程中创建Handler。查看源码:
1、new Handler()最终会调用下面的构造方法。
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();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
从代码中可以看出,由于Looper对象为null导致抛出异常。查看Looper.myLooper();方法
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
该方法返回一个和当前线程关联的Looper对像,如果调用线程未与Looper对线关联则返回null。抛出的异常中提示应该调用Looper.prepare()方法来为当前线程创建一个Looper对象。下面看下Looper.prepare()方法的具体内容:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
可以看到,首先判断sThreadLocal中是否已经存在Looper了,如果还没有则创建一个新的Looper设置进去。同时也可以注意到每个线程中最多只会有一个Looper对象。
2、之所以在主线程中创建Handler不会报错,是因为创建应用进程时为主线程创建了Looper对线,查看进程入口函数ActivityThread中的main()方法,Looper.prepareMainLooper();最终调用的还是Looper.prepare()方法。所以主线程中已经默认有Looper了,就不需要在创建Looper对象了。(新的进程会加载ActivityThread.java类)
public static void main(String[] args) {
......
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
......
/// M: ANR mechanism for Message History/Queue @}
Looper.loop();
}
二、Looper对象
Looper为线程维护一个消息循环队列MessageQueue,创建好了Looper对象,需要调用Looper.loop()启动Looper,从MessageQueue中读取消息。退出Looper可以调用Looper的quit()或者quitSafely()方法。下面看看Looper.loop()以及Looper的quit()和quitSafely()代码逻辑。
1、Looper.loop()
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
......
for (;;) {
Message msg = queue.next(); // 获取消息,可能会阻塞
if (msg == null) {
// No message indicates that the message queue is quitting.表示消息队列对出
return;
}
......
try {
msg.target.dispatchMessage(msg); //msg.target表示Handler对象
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
.......
}
2、查看下Handler对象的dispatchMessage(msg);方法
从loop方法中可知,从queue中获取消息后,通过msg.target获取消息对应的handler对象,并调用dispatchMessage方法进行消息处理。方法内部对判断回调接口,执行对象的方法。
public void dispatchMessage(Message msg) {
if (msg.callback != null) { //这里的消息callback是调用post()方法时传入的Runnable对象
handleCallback(msg); //执行Runnable的run方法
} else {
if (mCallback != null) { //这里的Callback是创建Handler对象时传入的,是Handler的内部接口。
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg); //handleMessage在Handler中为空实现,需要自己重写该方法。
}
}
通过上面代码的分析可以看出在调用Handler.post(Runnable r)更新UI线程原理的效果是完全等同于在handleMessage()方法中更新UI。
new Thread(new Runnable() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
// 在这里进行UI操作
}
});
}
}).start();
下面查看handler的post方法,定义了message的callback方法,可以看到对应的方法调用逻辑最终和send发送消息是一致的。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
另外两种线程中更新UI的原理和post是一样的性质。
1)View中的post()方法,代码如下所示:
public boolean post(Runnable action) { //handler是主线程中的对象
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
.......
return true;
}
2)Activity中的runOnUiThread()方法,代码如下所示:
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
3、Looper.quit()与Looper.quitSafely()退出
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
//两者最终调用MessageQueue中的quit方法:
void quit(boolean safe) {
......
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
......
}
}
removeAllMessagesLocked方法,该方法的作用是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送的需要延迟执行的消息)还是非延迟消息。
removeAllFutureMessagesLocked方法,通过名字就可以看出,该方法只会清空MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理,quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息。
无论是调用了quit方法还是quitSafely方法只会,Looper就不再接收新的消息。
三、消息发送
1、以sendEmptyMessage为例
public final boolean sendEmptyMessage(int what) {
return sendEmptyMessageDelayed(what, 0);
}
如果消息成功放入到消息队列MessageQueue中,则返回true,否则返回false。失败通常是因为处理消息队列的looper正在退出。返回true并不意味着消息一定会被执行到,如果在消息被处理之前Looper退出,则该消息将会被抛弃。
2、消息发送方法调用流程
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
3、接着调用到MessageQueue的enqueueMessage(Message msg, long when) 方法。
该方法主要将所有的消息按时间来进行排序,这个时间当然就是我们刚才介绍的uptimeMillis参数。具体的操作方法就根据时间的顺序调用msg.next,从而为每一个消息指定它的下一个消息是什么。
boolean enqueueMessage(Message msg, long when) {
.....
//如果消息recycle则返回false
if (msg.hasRecycle) {
Log.wtf("MessageQueue", "Warning: message has been recycled. msg=" + msg);
return false;
}
synchronized (this) {
if (mQuitting) { //线程在退出,返回false
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// 新的头消息,如果messagequeue阻塞,则唤醒
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//按时间顺序插入到消息队列中
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// 是否需要唤醒
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
四、综述
从handler中获取一个消息对象,把数据封装到消息对象中,通过handler的send…方法把消息push到MessageQueue队列中。
Looper对象会轮询MessageQueue队列,把消息对象取出。
通过dispatchMessage分发给Handler,再回调用Handler实现的handleMessage方法处理消息。
MessageQueue维护Message数据结构。
Handler的消息处理机制是线程安全的
关系:创建Handler之前需要创建Looper,Looper对象的创建又创建了MessageQueue。