1.概述
Handler的运行主要由三部分组成Handler,Looper,MessageQueue
Handler:主要功能是对Looper中的MessageQueue进行增删查操作。其方法分为4个系列obtainMessage用来创建Message;sendMessage(post最终调用的也为sendMessageDelayed)系列用来将Message加入MessageQueue;remove Messages/Callbacks根据条件删除队列中的item;hasMessages系列用力爱检查是否有对应的message。
Looper:循环处理MessageQueue中的Message,
MessageQueue:消息队列,主要关注next和enqueueMessage方法
Handler的使用中思考的一些问题:
- Handler中的任务在哪个线程执行,若向其中post耗时任务会不会ANR
- 一个耗时任务执行完时,已超过另外一个任务的开始执行时间后是如何处理的
- removeCallbacksAndMessages是否会删除MessageQueue中的所有数据
- 创建多个Handler是否会给系统造成较大压力
2.结构
3.源码分析
Looper
线程中Looper的创建顺序:prepare -> loop。当执行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(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......
msg.target.dispatchMessage(msg);
......
msg.recycleUnchecked();
}
}
final Looper me = myLooper();
首先获取当前线程的Looper,若未执行prepare则从ThreadLocal中get的Looper为空,抛出异常
然后进入for循环通过Message msg = queue.next();获取msg进行处理。
调用queue.next();会有三种情况
1.有需要执行的Message直接返回
2.Looper的quit或quitSafely被调用,返回null
3.block当前线程
当前面获取完成后进入msg的处理阶段
msg.target.dispatchMessage(msg);
调用的Handler的dispatchMessage进行后续处理。
msg.recycleUnchecked();
Message处理结束后进行重置,若Message pool未达到max的值则放入池中等待复用
至此消费者已经就绪,持续等待新消息的到来。
Handler
Handler的post系列方法以及sendMessage系列方法最终调用的都是sendMessageAtTime,进而进入enqueueMessage方法。enqueueMessage最终执行MessageQueue的enqueueMessage将msg加入队列
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
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) {
......
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
removeMessages、hasMessages同理都是对MessageQueue相应方法的调用封装。
MessageQueue
enqueueMessage
MessageQueue中Message的存储结构为单向链表,并且按when的值由小到大排列,成员变量mMessages指向首个元素。执行enqueue操作不一定就需要调用nativeWake唤醒block状态的Looper,需要根据插入的位置和msg类型等决定
boolean enqueueMessage(Message msg, long when) {
........
synchronized (this) {
//当调用quit方法后,mQuitting被置为true,新的消息不再处理
if (mQuitting) {
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添加FLAG_IN_USE,并更新when的数值
msg.markInUse();
msg.when = when;
//p为第一个要处理的Message
Message p = mMessages;
boolean needWake;
//若p为null则代表整个queue为空;若when为0或when < p.when表明新来的msg执行时间早于当前队首的item,插入到队首
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//当队首为barrier message时,enqueue异步任务,并且该任务的when早于队首的when则需要执行nativeWake
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
//遍历queue,queue中的第一个元素已经比较过了,从第二个开始
for (;;) {
prev = p;
p = p.next;
//p == null表示已到队尾,或者若when的值小于该元素的值则将新的msg插入到该元素之前
if (p == null || when < p.when) {
break;
}
//表示在新的msg之前还有需要执行的异步消息
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
//将新的msg插入到prev和p之间
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
next
enqueue进去的Message需要通过next获取
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
//注释很清楚,若执行了quit则指向NativeMessageQueue的指针mPtr为0,返回null
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//native层通过epoll的epoll_wait阻塞执行,等待管道写入信息或者达到nextPollTimeoutMillis指定的超时时间
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//若是一个barrier msg,则同步的msg无法执行,寻找下一个异步msg执行
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
//若还未到msg的执行时间,设置nextPollTimeoutMillis的值为msg.when - now
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
//将msg从队列中移除,解除引用添加FLAG_IN_USE
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
//若msg为null,表示队列为空,nextPollTimeoutMillis设置为-1同时执行后续代码
nextPollTimeoutMillis = -1;
}
//如果调用了quit,mQuitting为true,执行nativeDestroy并mPtr赋值为0
if (mQuitting) {
dispose();
return null;
}
//第一次遍历mMessages结束时pendingIdleHandlerCount的值为-1会进入下面代码块赋值,若mIdleHandlers不为空则pendingIdleHandlerCount的值会大于0
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
//若队列已空,并且没有要处理的IdleHandler,进入下次循环并block等待新的消息到来
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
//复制mIdleHandlers的内容
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
//遍历数组mPendingIdleHandlers,由于pendingIdleHandlerCount在循环结束时会被置为0,按上方的逻辑判断会将mBlocked = true同时continue,所以在同一次next方法中此循环只会执行一次
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
//解除引用
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
//从mIdleHandlers中移除,所以queueIdle返回值为false的从IdleHandler只会执行一次
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
removeCallbacksAndMessages
我们常用的Hander.removeCallbacksAndMessages(null),最终是由MessageQueue中的removeCallbacksAndMessages(Handler h, Object object)方法处理,其他几个remove逻辑基本一致,只是判断时增加了p.what == what和p.callback == r,本质上都是遍历链表mMessages并删除符合条件的节点
假设mMessages里的数据如图:红色为和传入Handler关联的Msg,需要删除
删除Message的的操作分为两部分
第一次循环,从链表头开始,Msg1不符合,循环结束p依然指向Msg1
第二次循环,从Msg1开始,遍历其后的所有的节点,并删除符合条件的节点,即Msg2,Msg4
void removeCallbacksAndMessages(Handler h, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
//从链表的首节点开始遍历,若符合删除并更新首节点的指向对象,即给mMessages重新赋值
while (p != null && p.target == h
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
//处理从下一个个到尾节点的数据
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
对于开始思考的结论:
1.Handler的任务执行线程取决于创建该Handler时传入的Looper,默认为Looper.myLooper()即创建该Handler时所处的线程。所以若Handler是在主线程(Activity,Fragment)中创建的则向其post耗时操作会导致ANR,若是在非主线程中创建则会阻塞该线程。
2.后续任务按时间顺序立即执行,即若队列前的任务占用了过多时间,无法保证指定的任务在指定的时间点执行,
测试代码如下,点击按钮向handler中添加三个Runable
findViewById(R.id.btn_handler_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
mHandler.post(new Runnable() {
@Override
public void run() {
Log.d(TAG, "start long running job");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
Log.d(TAG, "start delayed job");
}
},100);
mHandler.post(new Runnable() {
@Override
public void run() {
Log.d(TAG, "start short running job");
}
});
}
}).start();
}
});
由于第一个任务较为耗时,导致后续的任务需要顺延执行,Log如下,可见第二个任务是在5秒后开始的,并且任务插入时根据delay的时间排序(post方法delay为0)
08-03 17:59:14.113 11365-11365/com.gary.android.demoproject D/HanderActivity: start long running job
08-03 17:59:19.115 11365-11365/com.gary.android.demoproject D/HanderActivity: start short running job
08-03 17:59:19.117 11365-11365/com.gary.android.demoproject D/HanderActivity: start delayed job
3.每个线程中最多只能有一个Looper,以及一个MessageQueue,可以有多个Handler。所以当Handler执行removeMessages时只会删除当前Handler关联的Message。
4.如上所述,由于同一个线程中的多个Handler共用同一个Looper,所以在同一个线程中由于业务需要创建若干个Handler成本并不高
4.总结
当向Handler中post或send Message时首先需要明确其关联的是哪个线程,若是主线程则应尽量减少向其中添加任务,并且不应加入耗时操作,否则会影响界面的刷新、绘制等,造成界面卡顿甚至是ANR。
向类似HandlerThread线程中加入任务时要注意耗时任务与需要快速获得反馈任务的分离,如download job可能会导致该线程中其他任务的积压无法及时获得处理。