前面分析了Handler,MessageQueue,Looper之间是如何协作实现Android的消息机制的,但是还存在许多问题。比如:
-
Looper.loop是一个死循环,它是怎样退出的?当MessageQueue中没有Message的时候会发生什么? -
Message的异步和同步是什么?在处理的时候有什么区别?
看源码的时候不要纠结于细节,重点看流程。前面就是看流程,省略了很多细节,现在就来看前面没看到的细节。
首先看一下Message的源码。
从构造函数看起,Message的构造函数是空的,注释提示说建议使用obtain()来获取Message。
// obtain从全局池里获取Message实例,这在很多情况下可以避免不必要的创建
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
private static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
// 除此之外,还有多个obtain(...args),但是都会调用这个obtain(),只是用传入的...args为获取到的Message设置参数
显然这所说的全局池是一个单链表结构,sPool是链表首部,sPoolSize是链表长度。obtain从全局池中取出一个Message并返回,同时将Message的flags置0,只有当全局池为空时才创建Message。既然有取出Message,自然也应该有存入Message,即recycleUnchecked
void recycleUnchecked() {
// 设置flags,标识Message被使用,并清除其他变量
flags = FLAG_IN_USE;
what = 0;arg1 = 0;arg2 = 0;obj = null;replyTo = null;sendingUid = -1;
when = 0;target = null;callback = null;data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
这个方法用于回收Message,设置待回收的Message的实例变量(但是将flags设置为FLAG_IN_USE,是表示回收之后才被使用吗?3⃣️),将其存入全局池。照例全局池的大小是有限制的,也需要注意同步。从方法名看这个方法没有做检查,检查是什么,看另一个方法recycle()
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
/*package*/ boolean isInUse() {
return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}
由此可见,flags设置为FLAG_IN_USE表示Message被使用了,说明已经被回收了,就不要再回收了,这是检查。还有一个gCheckRecycle变量,这是适配用的,在updateCheckRecycle中设置,当API小于21时,将其设置为false。为什么要做这个适配呢?4⃣️
再看其他的方法,setAsynchronous将设置flags,将Message设置为异步模式,异步模式的Message不遵守Looper的同步屏障(synchronization barrier)。根据方法注释,某些操作比如view invalidation,可能在Looper的MessageQueue中设置同步屏障,以防止后续的Message在某些条件满足之前被传递。在view invalidation的情况下,调用android.view.View#invalidate发出的Messages会被各种同步屏障挂起,直到下一帧准备好绘制。同步屏障可以确保在恢复之前完全处理无效请求。
异步消息不受同步障碍的影响。它们通常表示中断、输入事件和其他必须独立处理的信号,即使其他工作已经挂起。尽管异步消息内部总是按顺序传递, 但相对于同步消息可能不按顺序传递。如果这些消息的相对顺序很重要, 那么它们不应该是异步的。
使用isAsynchronous方法可以判断Message是否是异步的。
/*
获取与此Message相关的任意数据的Bundle,并且在必要的时候懒惰创建它。调用setData(Bundle)来设置这个值。使用Messenger跨进程传递数据的时候,需要通过Bundle#setClassLoader(ClassLoader) Bundle.setClassLoader()来在Bundle上绑定ClassLoader,以便能够在检索他们的时候能够实例化对象。
*/
public Bundle getData() {
if (data == null) {
data = new Bundle();
}
return data;
}
//类似于getData,但是不能懒惰创建Bundle。如果Bundle没有存在,就返回null。
public Bundle peekData() {
return data;
}
//使用Message持有的Handler发送自己。
public void sendToTarget() {
target.sendMessage(this);
}
// 拷贝一个Message,不包括链表域next,sPoolSyns等,时间戳when和持有的Handler与回调方法Callback
public void copyFrom(Message o) {
this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM;
this.what = o.what;
this.arg1 = o.arg1;
this.arg2 = o.arg2;
this.obj = o.obj;
this.replyTo = o.replyTo;
this.sendingUid = o.sendingUid;
if (o.data != null) {
this.data = (Bundle) o.data.clone();
} else {
this.data = null;
}
}
接下来看一下没有涉及到的实例变量和类变量
/*
用户定义的message code,用于标志Message的用途。每个Handler都有它自己的变量空间,不用担心命名冲突
*/
public int what;
/*
arg1和arg2可以用来存储少量数据,如果数据多再用data(Bundle)
*/
public int arg1;
public int arg2;
/*
可以发送给接收方的对象。使用Messenger跨进程发送Message的时候,如果Message包含一个序列化(Parcelable,API8之前不支持)的框架类(framework class,不是应用实现的类)。传输其他数据则使用setData
*/
public Object obj;
/*
可选的Messenger,用于接收这个Message。具体的使用方法有发送者和接受者规定。
*/
public Messenger replyTo;
/*
可选的域,表明发送这个Messsage的uid,只对Messager发送的Messages有效。否则为-1。
*/
public int sendingUid = -1;
/*
Message触发的时间
*/
long when;
/*
Message自带的回调方法,前面讲Handler的时候提到过处理消息的方法dispatchMessage(Message)首先考虑调用的就是Message自带的回调方法。其次考虑调用MessageQueue的回调方法,最后才考虑Handler的handleMessage()
*/
Runnable callback;
Message分析完了,暂时不考虑跨进程的功能,接下来分析Looper和MessageQueue,因为MessageQueue是和Looper一起创建的,所以一起看比较方便。先看构造函数:
// Looper的构造函数
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
final MessageQueue mQueue;
final Thread mThread;
// MessageQueue的构造函数
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
// True if the message queue can be quit.
private final boolean mQuitAllowed;
@SuppressWarnings("unused")
private long mPtr; // used by native code
mQuitAllowed为true,表示MessageQueue能退出,在quit()里也能用到,主线程的MessageQueue的mQuitAllowed为false,不能退出,可以看到prepareMainLooper()中调用了prepare(false),最终传到MessageQueue的构造函数。而一般在子线程中创建Looper时,调用prepare(),默认设置设置mQuitAllowed为true,因此子线程的MessageQueue可以退出。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
再来看Looper与MessageQueue的退出,Looper的退出有两种,内容是退出其持有的MessageQueues
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
quit与quitSafely的区别在于:
quit终止loop方法,不用处理MessageQueue里剩余的Messages。
quitSafely等待MessageQueue中剩余的Messages(不包括等待延迟的Messages)被处理完之后才终止loop方法。等待延迟的Messages指触发时间在当前时间之前但是还在MessageQueue中的Messages。
在Looper退出之后,任何发送Message的方法(比如Handler#sendMessage(Message))都会返回false。
使用quit可能导致某些Messages不被处理,因此建议使用quitSafely
Looper的退出方法内部调用了MessageQueue的quit方法。
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
MessageQueue的实例变量mQuitting表示队列是否退出。这里最终调用本地方法nativeWake(mPtr)来退出队列。对于quit,移除MessageQueue中的所有Messages,对于quitSafely,移除MessageQueue中所有没有等待延迟触发的Messages。
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {
removeAllMessagesLocked();
} else {
Message n;
for (;;) {// 找到MessageQueue中在现在之后触发的Messages
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();//回收Message
} while (n != null);
}
}
}
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
接下来再看Looper的loop方法
public static void loop() {
// 清空远程调用端的token,设置当前线程的token并存入ident
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// 如果Message为空,默认为MessageQueue为空,退出loop
return;
}
// 当Message处理的时间超过slowDispatchThresholdMs时,就会报警
final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
//开启跟踪日志
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();//消息处理的开始时间
final long end;//消息处理的结束时间
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
//关闭跟踪日志
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (slowDispatchThresholdMs > 0) {
final long time = end - start;//消息处理的耗时
if (time > slowDispatchThresholdMs) {//消息处理超时了,报警
Slog.w(TAG, "Dispatch took " + time + "ms on "
+ Thread.currentThread().getName() + ", h=" +
msg.target + " cb=" + msg.callback + " msg=" + msg.what);
}
}
// 再次获取当前线程的token,检查操作前后token是否有变化
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
// 报告一个异常 - What a Terrible Failure
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();
}
}
private long mSlowDispatchThresholdMs;
这里的知识点有Binder通信时的token5⃣️,独立于方法的跟踪日志(Trace)6⃣️,还不了解,但是不影响理解。通过MessageQueue的next方法取出Message,如果Message为空则说明MessageQueue已经退出,退出Looper的loop方法。否则调用Message持有的Handler来处理Message。这里还指定了这个处理过程的耗时限制,如果超时了就会打印Warning日志。处理完之后调用Message的recycleUnchecked回收Message。
Handler也分析完了,现在从MessageQueue的next方法开始进入MessageQueue的源码分析。
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;//在下一个Message可以触发之前需要等待的时间
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();//清理等待的Binder指令
}
//等待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;
if (msg != null && msg.target == null) {
// 如果Message不为空但是未持有Handler,则说明他被同步屏障拦截了,那么后面的同步Message都被同步屏障拦截了,可以先找异步Message来处理。
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
//现在找到一个可以处理的Message了,不管他是同步的还是异步的
if (msg != null) {
if (now < msg.when) {
// 如果Message触发的时间还没到,则说明现在没有可以执行的Message,需要等待,因此计算出等待的时间nextPollTimeoutMillis
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 获取一个Message,需要清除阻塞标志,并将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;
}
// 如果已经quit了,则回收MessageQueue并返回null,Looper的loop接收到null,就知道MessageQueue退出了,会退出loop方法,能走到这一步说明MessageQueue中没有Message或者只有被同步屏障拦截的Message了
if (mQuitting) {
dispose();
return null;
}
// 如果Message队列还没有创建,或者所有Messages都还没有到触发的时间,则重新计算空闲的Handler的数量
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
// 如果没有空闲Handler,则设置阻塞标志,进入阻塞状态
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
// 创建一组空闲Handler
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// 执行到这里说明没有可用的Message,但是Looper还没有退出,而且还存在空闲的Handler
//采用相应的策略来决定是否回收空闲的Handler,这个策略由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 {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
这里的知识点在于,mPtr是什么?当它为0的时候,Looper已经退出了。可以发现处理同步Message的Handler是有限的,如果没有空闲的Handler,就会陷入阻塞。另外还有Binder.flushPendingCommands(),nativePollOnce,IdleHandler等。只有在Looper调用了quit之后MessageQueue的next才会返回null,Looper的loop才会退出,否则即使MessageQueue里已经没有Message了,loop也只是继续等待。
然后看enqueueMessage
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) {
// 如果MessageQueue已经退出了,那么回收这个新插入的Message,并返回false
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();//将Message标记为使用中
msg.when = when;//设置Message的触发时间
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// 将Message插入到MessageQueue的队列头部,此时需要唤醒
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 按照触发时间的顺序将Message插入到MessageQueue的队列中部,如果之前由于缺少空闲Handler而引起阻塞,则需要唤醒
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.
// 调用native方法来唤醒MessageQueue
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}

本文深入探讨了Android消息机制的工作原理,重点分析了Message、MessageQueue、Looper之间的协作方式及其实现细节,包括消息的异步与同步处理、消息队列的管理与退出机制。
1137

被折叠的 条评论
为什么被折叠?



