作者:森林深处没有鹿
转载地址:https://juejin.cn/post/7100845669014831118
本文着重于对Handler整体的流程,Looper、MessageQueue、Message、Handler之间如何相互协作运行,sendMessage到handlerMessage之间的代码执行流程。
Looper
UI线程Looper的创建
handler 的创建线程是需要Looper的,UI线程不需要手动创建,在ActivityThread的main方法里被自动创建。
public final class ActivityThread extends ClientTransactionHandler {
public static void main(String[] args) {
Looper.prepareMainLooper();
Looper.loop();
}
}
通过Looper.prepareMainLooper()创建UI线程Looper对象,内部调用Looper的 prepare() 方法
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
sMainLooper = myLooper();
}
}
子线程Looper创建
除UI线程外的子线程,需要手动创建Looper,创建方法也是通过Looper.prepare() 和UI线程手动创建Looper的方式一致。
// 创建
Looper.prepare();
// handler 相关代码
// 启动
Looper.loop();
Looper.prepare() 会把创建的Looper对象存入ThreadLocal。
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));
}
ThreadLocal 是一个线程内部的存储类,可以把数据存储在指定线程内,存储数据后,只能在指定线程才能获取到存储的数据。
Looper的初始化方法内,会创建MessageQueue对象并作为其成员变量
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Handler
在Handler 初始化时,会通过ThreadLocal获取当前线程的Looper, 以及Looper内的 MessageQueue;线程内没有Looper会报错;
public Handler(@Nullable 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;
}
在发送消息时,大致有三种方式:
handler.sendMessage;
handler.obtainMessage;
handler.post(runable);
三种方式本质都是同一种实现,差异仅在对Message的处理:
sendMessage 需要我们new Message对象
obtainMessage 会获得Message的单例对象
post(runable) 先通过obtainMessage获得Message对象,然后设置Message的Callback属性
最终都会通过sendMessage方法,调用到MessageQueue的enqueueMessage来实现的。
调用链如下:
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull 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);
}
public boolean sendMessageAtTime(@NonNull 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);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
在queue.enqueueMessage(msg, uptimeMillis),就进入到MessageQueue类。
MessageQueue
MessageQueue虽然叫做消息队列,但内部实现是使用单链表的数据结构,来维护消息列表。主要包含两个操作:enqueueMessage(..) 插入数据,next() 读取数据;
enqueueMessage(..)主要实现了单链表的插入:
boolean enqueueMessage(Message msg, long when) {
...
synchronized (this) {
...
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
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 {
// 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) {
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;
}
next() 方法源代码过长就不放出了,主要原理是通过死循环,消息队列无消息就阻塞,有消息会返回该消息并从链表中将该消息删除。
在MessageQueue中有了新消息,Looper就会立即检测到。
Looper
Looper.loop() 方法内有一个死循环,不停的通过messageQueue.next() 检查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;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
Looper检测到新消息是,会调用 msg.target.dispatchMessage(msg)来处理消息。前面我们提到,target就是发送这条消息的Handler对象。
线程在这里被切换:
dispatchMessage(msg) 是在Looper内被执行的,这里的Looper正是创建Handler时,线程里环境必要的Looper,这样dispatchMessage(msg) 方法就被切换到Handler创建时的线程了。
这时,由Handler发送的消息又回到了Handler内部,由dispatchMessage(msg)。
Handler
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
这里处理了三种情况:
- 方法内的callback正是我们前文提到的Handler.post(Runnable)方式下设置的callback
private static void handleCallback(Message message) {
message.callback.run();
}
这里执行run()方法,已经达到切换线程的目的了。
方法内的 mCallback 是不使用Handler派生类来创建的Handler,继承自Callback接口
public interface Callback {
boolean handleMessage(@NonNull Message msg);
}
方法内的handlerMessage(msg)正是我们继承Handler重写的 handlerMessage()方法。
到这里,从sendMessage 到 handlerMessage,中间的过程已经跑通了。
handler 整体流程总结
1.在Handler 初始化时,会获取当前线程的looper, 以及 MessageQueue;
2.handler.SendMessage 方法最终会调用MessageQueue.enqueueMessage(), 将Message插入到MessageQueue链表中,并将Handler 本身赋值给Message 对象的target属性;
3.MessageQueue在将Message插入到队列后,Looper里的Looper方法会检测到新消息出现,并开始处理消息;
4.Looper.Loop方法从消息队列里面获取到message后,通过traget属性拿到Handler对象,正是我们enqueueMessage放入的handler 对象;
5.调用handler对象的dispatchMessage方法,最终会走到我们继承于Handler的handlerMessage方法,来处理具体的业务;
网友评论