Handler 的工作流程
创建,定义处理逻辑:
// 某个 Activity 中
// 子线程才需要执行,否则新建 Handler 会报错
Looper.prepare();
// 创建的时候,需要实现 handleMessage 函数
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
// do something
}
};
// 子线程才需要执行,否则收不到消息
Looper.loop();
Handler 的构造函数有多个,但其实终究归类为两种:
「不带 Looper 实例的」和「带 Looper 实例的」。
Handler 的构造函数源码:
// 代码段a0
// .../Android/sdk/sources/android-28/android/os/
// Handler.java
/**
* 不带 Looper 实例,那就会自己创建一个 Looper 实例;
* 通过 Looper.myLooper() 来创建一个 Looper 实例 mLooper。
* mLooper 是和当前线程绑定的,
* mLooper 在被创建时,其构造函数,会创建一个 MessageQueue 实例 mQueue,
* 同时此处的 Handler 实例也会拿到 mQueue 实例的引用。
*
* 所以可以这样说:Handler 实例在创建时,
* 会绑定一个 Looper 实例 mLooper 和 一个 MessageQueue 实例 mQueue,
* 并且,Looper 实例 mLooper 又是和当前线程绑定的。
*/
public Handler(Callback callback, boolean async) {
.....
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 实例,则不用再创建一个 Looper 实例
* 直接赋值就行
*
*/
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Looper 的构造函数 和 myLooper( ) 函数:
// 代码段a1
// .../Android/sdk/sources/android-28/android/os/
// Looper.java
private Looper(boolean quitAllowed) {
// 新建一个队列
mQueue = new MessageQueue(quitAllowed);
// 取得当前线程的引用
mThread = Thread.currentThread();
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
// 返回当前线程的 Looper 实例
return sThreadLocal.get();
}
发消息的用法示例:
// 发送一个消息
Message message = new Message();
message.obj = "I am a message";
mHandler.sendMessage(message);
// post 一个线程
mHandler.post(new Runnable() {
@Override
public void run() {
LogUtil.e("当前线程:" + Thread.currentThread().getName());
}
});
注意这个动作是可以在别的线程中执行的,因为 mHandler 实例是一个对象,线程共享。
goto sendMessage(message)
和 post(new Runnable(){...})
// 代码段0:
// Handler 类
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
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);
}
到此可知,最终调用了 enqueueMessage 函数进行入队处理。
再看 post 函数源码:
// 代码段0.1:
// Handler 类
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;
}
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool; // 从线程池里取一个 Message 实例
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
post 函数提交的 Runnable 实例,会被放入 Message 实例的成员变量 callback 中,接着调用
sendMessageDelayed 函数继续流程,以 Message 实例的形式继续传递。
到此可知,无论调用 sendMessage 函数还是 post 函数,最终都会调用 sendMessageDelayed 函数,进而调用 enqueueMessage 函数把消息 msg 入队。
// 代码段1:
// Handler 类
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; //入队前,记录所属的 handler
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
// 代码段2:
// MessageQueue 类
boolean enqueueMessage(Message msg, long when) {
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) {
// 如果表头为空 or 延迟时间为0 or 延迟时间比表头时间少
// 则插入表头
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 否则插入中间
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next; // 从表头往后遍历
if (p == null || when < p.when) { // 按 when 的早晚排序,若when相等,后入队的排后面,例如,2,3,5;入队是 3,那么循环到 p.when == 5 的时候break;
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;
}
可知 queue 中,message 以链表的形式存储,按执行事件的早晚,即 when 由小到大排序,若when相等,后入队的排后面。
在 new Handler 之前,需要在当前线程通过委托 Looper.prapare() ,new 一个 Looper 实例并存到当前线程的线程本地 map (即 当前线程实例的成员变量 threadLocals)中,从而实现绑定当前线程 。
Looper.prapare() 之后,执行 new Handler(),然后在当前线程执行 Looper.loop() 开启消息循环,Looper 不断从队列里取消息。否则刚刚 new 的 Handler 收不到消息。
在 Looper.loop() 函数内,不断从消息队列中取消息,
再把消息分发到其 target 的 dispatchMessage(msg) 函数处理。
去看 Looper.loop() 函数源码:
// 代码段3:
// Looper 类
public static void loop() {
// 3-0,取出当前线程的 Looper 实例 me
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 3-1,通过当前线程的 Looper 实例 me,取出队列实例,
// 所以可以说,取出当前线程的 MessageQueue 实例 queue
final MessageQueue queue = me.mQueue;
......
for (;;) {
// 3-2 处,当前线程的 MessageQueue 实例 queue 取出消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
// 3-3 分发给所属的 Handler 实例,参考代码段1
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
......
msg.recycleUnchecked();
}
}
注释 3-0,3-1 处,可知,消息循环是依赖当前线程的 Looper 实例 和 MessageQueue 实例进行的;
注释 3-2 处,在 for 循环中,不断的从当前线程的 MessageQueue 实例取出消息,并做一些判断,然后在当前线程处理。
这里可以引出线程切换问题:
此处取出的消息,是由本线程创建的 Handler 实例发送进来的,而 Handler 实例是线程共享的;
因此,可以做到线程切换的效果:
由别的线程引用了当前线程创建的 Handler 实例并发送消息过来,
然后在当前线程处理消息。
那其他线程可以引用到本线程的
Q: 其他线程可以拿到当前线程的 MessageQueue 实例吗?
通过 Handler 实例的 getLooper().getQueue() 可以拿到。
Q: 开发者通过其他线程拿到当前线程的 MessageQueue 实例后,可以执行线程循环吗?
不行,开发者即使拿到 MessageQueue 实例,因为 next( ) 函数是默认缺省修饰符,不同包是无法访问的。
源码如下:
// .../Android/sdk/sources/android-28/android/os/
// MessageQueue.java
Message next() {
.....
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// native 层调用
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;
/** 如果表头不空,但是 表头消息没有 handler
* 则向后遍历
*/
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());
// 直到找到一个 msg 不空,且是异步的
// 同步屏障的意义就在于先取异步消息来执行
}
if (msg != null) {
// 没到执行时间,等过 nextPollTimeoutMillis 这段时间再唤醒
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 {
// 找到可以执行的 msg
// 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;
}
......
}// end for (;;)
}
默认缺省的修饰符,只能在同类或同包下调用 next( ) 函数,
而在 “…/Android/sdk/sources/android-28/android/os/” 该包下,
仅有 Looper类的静态函数 looper( ) 中,调用了 next( ) 函数;
换句话说:Looper.looper( ) 是开启线程循环的唯一入口。
再回到 代码段3 的注释 3-3 处,msg.target 得到的是 msg 所属的 Handler 实例, 代码段1的 Handler 类的 enqueueMessage 函数把消息入队之前,赋值自身 this 给 msg.target 。
所以,msg.target.dispatchMessage(msg) 调用的是 Handler 类的 dispatchMessage 函数。
小结:
Looper.loop() 函数内用死循环,不断调用消息队列里的 next 函数取消息;
而消息队列里的 next 函数内又有死循环,所以可能会阻塞。
消息队列本质是以链表的形式存储消息的。
取消息的原则:
首先取表头消息,如果 target 为空,再往后找,
直到找到 target 不为空的排最早的消息,然后再进入下一个判断;
下一个判断:
根据消息的延迟时间,判断是否可以立刻执行?
若消息还不是立刻执行,就休眠一会;若消息可以执行,就分发给 target 的 dispatchMessage 函数处理。
// 代码段4
// Handler 类
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 4-1 表示由 post 函数发送的 Runnable,参考代码段0.1,post 函数的源码可知
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) { // 4-2 如果有回调处理了,直接返回
return;
}
}
handleMessage(msg); //4-3 最后才叫给 handleMessage 函数
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
值得注意的是 4-2 处,mCallback 是在构造函数传进来的。
构造函数 和 Callback 的定义:
// 代码段4.1
// Handler 类
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Callback callback, boolean async) {
// 。。。
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;
}
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public boolean handleMessage(Message msg);
}
代码段4中,如果 mCallback.HandleMessage 返回 true,就表示处理了,就不会走 4-3 处的 handleMessage 函数。
Handler 的工作流程
创建,绑定线程特有的 Looper 实例
发消息 Handler#sendMessage 或 Handler#post
入队 MessageQueue#enqueueMessage()
消息循环 Looper.loop()
分发处理 Handler#dispatchMessage