「这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战」
Handler机制原理
3.MessageQueue之quit
quit 方法退出消息列表,通过参数 safe 决定是否直接退出
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);
}
}
通过saft参数判断要移除的消息,removeAllFutureMessagesLocked()移除尚未处理的消息。
removeAllMessagesLocked移除所有的消息。
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {
removeAllMessagesLocked();
} else {
Message n;
for (;;) {
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();
} while (n != null);
}
}
}
会根据当前消息的时间。判断他是否正在处理,等待消息处理完后再去删除所有的消息。
4.Handler
Handler是一个使用最频繁的类,主要用于消息的发送和处理。
先分析以下他的构造方法。
public Handler(@Nullable Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
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;
}
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
在初始化的过程中,首先会去获取当先线程的Looper实例mLooper,如果不存在则抛出异常。抛出的异常有些同学可能很眼熟,由这里可以知道,当我们在子线程使用Handler的时候要手动调用Looper.prepare()创建一个Looper对象,之所以主线程不用,是系统启动的时候帮我们自动调用了Looper.prepare()方法。 然后去关联Looper中的 MessageQueue 消息队列。
UI 线程在启动时会自动创建 Looper 实例,所以一般我们在 UI 线程中使用 Handler 时不需要传递 Looper 对象。而在子线程中则必须手动调用 Looper.prepare 和 Looper.loop 方法,并传递给 Handler ,否则无法使用。 在以前的文章中对这部分有介绍。
\