首先要知道关于handler四个重要成员
Handler:负责消息的分发与处理
Looper:轮子,跟handler绑定,负责从消息队列里轮询取message供handler处理
MessageQueue:消息队列,负责存储handler要处理的message
Message:顾名思义就是消息,平时用来承载事件的类别及事件内容
1、一个线程里可以有几个handler,几个looper,几个MessageQueue
答:一个线程里可以创建多个handler,一个looper和一个MessageQueue
//handler构造函数
public Handler(@Nullable Callback callback, boolean async) {
//初始化的时候就需要当前线程中有Looper对象,否则会抛出异常
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
//looper初始化
private static void prepare(boolean quitAllowed) {
//从这里可以看到线程中有且只能有一个looper,否则就会抛异常
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//将looper保存到ThreadLocal里
sThreadLocal.set(new Looper(quitAllowed));
}
//初始化的同时创建了MessageQueue,到这里可以理解一个线程中handler可以有多个,但是looper和
//MessageQueue有且只能有一个
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//安卓入口函数调用的,可以看到启动APP的时候,就默认在主线程创建了looper
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
2、同一个线程中多个handler把消息放入同一个MessageQueue,那么在消息要即将分发的时候是如何找到对应的handler来处理的
主要是用到了message里的target变量,将target设置为当前的handler,在消息分发的时候通过target找到对应的handler
//hanlder的sendMessage方法最终会调用enqueueMessage,将消息插入到消息队列中
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
//这里为message设置了target为当前handler
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
//looper里的loop方法,轮询MessageQueue,从消息队列里取数据
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;
}
try {
//msg.target就是对应的handler,调用了handler的dispatchMessage
//所以我们平时创建handler实现dispatchMessage方法,在dispatchMessage就能收到消息
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
} finally {
}
(.....省略代码......)
msg.recycleUnchecked();
}
}
3、handler的同步屏障
同步屏障是为了屏蔽同步消息,优先处理异步消息,我们平时创建的消息都是同步消息,假如消息队列有大量的同步消息,此时需要处理一个紧急的消息(比如view的更新、触摸事件的分发),就可以把该消息作为异步消息,开启同步屏障之后,优先处理紧急的消息。
MessageQueue里的方法
postSyncBarrier:开启同步屏障
removeSyncBarrier:移除同步屏障
//MessageQueue的开启同步屏障方法
private int postSyncBarrier(long when) {
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
//可以看到同步屏障的消息类型里是没有target的
msg.markInUse();
msg.when = when;
//记录当前的token
msg.arg1 = token;
Message prev = null;
//将同步屏障的消息放到消息队列的第一个
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
//MessageQueue的开启异步屏障方法
@TestApi
public void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
// If the queue is no longer stalled by a barrier then wake it.
synchronized (this) {
Message prev = null;
Message p = mMessages;
//查找消息队列里的同步屏障消息,然后移除掉
//如果p不是null,并且target为null,并且token匹配成功,那么p就是要找的同步屏障消息
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
prev.next = p.next;
needWake = false;
} else {
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;
}
p.recycleUnchecked();
//判断是否需要唤醒looper去消息队列里轮询
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
//MessageQueue消息入队列
boolean enqueueMessage(Message msg, long when) {
//消息必须是有被分发者(hanlder)的
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//消息必须是没有被消费使用的
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
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.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
//如果队列没有消息 或者消息是即时的 或者当前要入队的消息比头部消息时间还靠前
//把当前的消息放到队列头部
msg.next = p;
mMessages = msg;
//如果消息队列处于阻塞状态,那么就需要唤醒来轮询
needWake = mBlocked;
} else {
//在队列中间插入。通常我们不必唤醒事件队列,除非在队列的头部有一个障碍,并且消息是队列中最早的异步消息
needWake = mBlocked && p.target == null && msg.isAsynchronous();
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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
//唤醒消息队列
nativeWake(mPtr);
}
}
return true;
}
//MessageQueue取消息
@UnsupportedAppUsage
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.
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();
}
//根据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;
//同步屏障消息的特殊标记(target为null)
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) {
if (now < msg.when) {
// 如果当前时间还没有到消息的处理时间,那么就计算一下还得需要多久才能到处理的时间,这样的话就可以根据这个时间阻塞等待着
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
//时机符合,取出该消息
mBlocked = false;
//这里就是消息取出之后改变链表的前后联系
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 {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
//每次消息轮询的时候pendingIdleHandlerCount为-1
//并且消息队列没有消息或者队列第一个消息还没有到达处理的时间
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
mBlocked = true;
continue;
}
//初始化mPendingIdleHandlers
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
//当消息队列的消息没有或者当前不需要处理消息的时候(空闲期)
//就会执行IdleHandler(其实是个接口)
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 {
//执行IdleHandler实现的queueIdle方法
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
//如果queueIdle方法返回false,那么该IdleHandler就会被移除
//否则的话queueIdl会一直在mIdleHandlers里,只要消息队列空闲,那么就会执行IdleHandler的IdleHandler方法
mIdleHandlers.remove(idler);
}
}
}
//重置pendingIdleHandlerCount
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
4、handler的postDelayed原理
postDelayed方法里需要传入一个runnable,runnable作为message的callback变量,在消息入消息队列的时候,会根据delay的时间远近依次插入到消息队列里,每次消息队列取消息的时候,都会根据队列的首个消息来判断是否到了可分发的时间,如果没有到那么就阻塞等待,到了时间就被唤醒去取消息。
//最终还是封装成一个message,把runnable作为message的callback变量
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
@UnsupportedAppUsage
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
//handler在dispatchMessage的时候,如果callback不是null,那么就调用handleCallback方法
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
//最终执行了runnable实现的run方法
private static void handleCallback(Message message) {
message.callback.run();
}
5、Looper.loop()方法用了死循环为啥不会把应用程序卡死
Android是事件驱动,在APP启动的时候主线程的looper就已经默认创建,只有APP退出looper才会停止,APP运行期间如果没有消息要处理那么就会执行MessageQueue.next()方法里的nativePollOnce进行阻塞,等待时机的到来。消息队列阻塞期间,主线程就会释放cpu资源占用进入休眠状态,直到延迟唤醒时间到来或者有新的消息插入到队列头部,再唤醒线程去处理消息。
6、IdleHandler是个啥
IdleHandler不是一个handler,而是一个接口,需要实现queueIdle方法,该接口存在于MessageQueue中,当消息队列里没有消息或者消息暂时不需要处理(延时处理),就会执行IdleHandler的queueIdle方法。
//使用方法
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
//此处可以写自己的业务逻辑代码
//true:执行完之后不会移除掉,每当消息队列空闲的时候就会执行
//false:执行一次就会移除
return false;
}
});
//MessageQueue的方法
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
//将IdleHandler实现类放到mIdleHandlers(list集合)中
mIdleHandlers.add(handler);
}
}
public void removeIdleHandler(@NonNull IdleHandler handler) {
synchronized (this) {
//从mIdleHandlers集合移除
mIdleHandlers.remove(handler);
}
}
//消息轮询取出
@UnsupportedAppUsage
Message next() {
(....忽略代码.....)
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
(....忽略代码.....)
//消息队列没有消息或者消息还未到执行时间
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
//计算一下mIdleHandlers数量
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
mBlocked = true;
continue;
}
//初始化mPendingIdleHandlers(数组)
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
//将集合转换成数组
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
//遍历mPendingIdleHandlers数组 去执行IdleHandler里的queueIdle方法
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);
}
//queueIdle返回false的话,就会移除queueIdle这样就保证只执行一次
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
//重置pendingIdleHandlerCount,这样在当前一次消息轮询(Looper调用MessageQueue的next)的时候不会重复执行
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}