Handler 源码解析
Handler
子线程与主线程之间的沟通中介,用于传递消息。
基本使用
创建 Handler 对象,重写 handlerMessage 方法
Handler handler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
// 处理消息
}
};
发送消息
Message message = Message.obtain();
message.what = 1;
handler.sendMessage(message);
源码解析
Handler 的运行依赖 MessageQueue、Looper,MessageQueue 是消息队列,用于存放 Handler 发送的消息,Looper 会无限循环查找消息队列中的消息,有消息就取出,没有就等待。
Looper
对消息队列(MessageQueue)进行循环,获取消息(Message)给 Handler 处理。
Looper 通过 prepare 创建 Looper 对象,每个线程只允许创建一个 Looper 对象,并将创建的对象保存在 sThreadLocal 中。在主线程中创建 Handler 时,不需要自己创建 Looper,系统运行时就帮我们创建了 Looper .
public final class Looper {
...
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
final MessageQueue mQueue;
final Thread mThread;
public static void prepare() {
prepare(true);
}
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));
}
// 由 Android 环境创建,在 ActivityThread 中的 main 方法
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static void loop() {
...
for (;;) {
// 循环从消息队列中取消息
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // 取到消息
...
try {
// 处理消息,msg.target 是 Handler
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
}
...
}
...
}
ActivityThread
应用程序创建的时候,系统会调用 ActivityThread 的 main 方法,创建 Looper 并 调用 loop 方法,使 Looper 开始轮询起来。
// ActiivtyThread 类
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
}
Handler
用来发送消息(sendMessage)和处理消息(handleMessage)。
Handler 对象被创建的时候,会将 Looper 的 mQueue 赋值给 Handler 的成员变量 mQueue,发送消息 sendMessage 最终调用到了 enqueueMessage 方法,把消息加入到消息队列中。
public class Handler {
...
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
this(looper, callback, false);
}
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
// 处理消息,由 Looper 触发
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
...
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);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;// 将在 handler 本身赋值给 msg 的 target
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
}
MessageQueue
消息队列,存放 Message,以链表的方式实现。
消息在加入到队列时,会根据 delay 的时间,插入到队列中合适的位置,保证队列的顺序是按照延迟时间从小到达进行排序。方便在后续获取消息的时候,直接获取到队头消息。
public final class MessageQueue {
...
// 将消息加入到队列
boolean enqueueMessage(Message msg, long when) {
...
synchronized (this) {
// 检查Looper及相应的队列是否已经终止
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 不需要延时 或 msg 需要延时时长小于队列消息的延时时长
// 则将 msg 插入消息队列头部
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;
}
...
// 获取一个消息
Message next() {
...
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// 头部消息还没到执行时间,调用本地方法进行阻塞挂起
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) {// 判断是否有消息屏障
// 有消息屏障的话,取出后面的第一条异步消息
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 {
// 此时有消息到了执行时间,则设置队列处于不阻塞状态
// 将队头出队,返回
mBlocked = false;
// 有消息屏障的情况下,将链表的前部分的同步消息连接到后面
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {// 否则,直接将mMessages指向下一个消息即可
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// 如果没有消息,则设置阻塞时长为无限,直到被唤醒
nextPollTimeoutMillis = -1;
}
if (mQuitting) {
dispose();
return null;
}
// 第一次循环 且 (消息队列为空 或 消息队列的第一个消息的触发时间还没有到)时,
// 表示处于空闲状态,获取到 IdleHandler 数量
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// 没有 IdleHandler 需要运行,循环并等待
mBlocked = true;// 设置阻塞状态为 true
continue;
}
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 {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// 重置 IdleHandler 的数量为 0,确保不会重复运行
pendingIdleHandlerCount = 0;
// 在执行 IdleHandler 后,可能有新的消息插入或消息队列中的消息到了触发时间,
// 所以将 nextPollTimeoutMillis 置为 0,表示不需要阻塞,重新检查消息队列
nextPollTimeoutMillis = 0;
}
}
}
消息类型
Handler 的消息类型有三种:同步消息、异步消息、消息屏障。
同步消息
Message message = Message.obtain();
message.what = 1;
handler.sendMessage(message);
异步消息
Message message = Message.obtain();
message.what = 1;
message.setAsynchronous(true);// 异步消息设置
handler.sendMessage(message);
消息屏障
添加消息屏障的方法是 @hide 的,需要通过反射调用,该方法会返回该消息的 token ,移除消息屏障需要用到这个 token .
消息屏障用来阻塞消息队列后面的同步消息,而异步消息不受消息屏障的影响。在无消息屏障的情况下,同步消息和异步消息没有区别。
/**
* MessageQueue类
* 添加一个消息屏障
*
* @hide
*/
@UnsupportedAppUsage
@TestApi
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
内存泄漏
Handler 的内存泄漏原因在于发送延时消息,Handler 发送延时消息到 MessageQueue 中,MessageQueue 持有 Message 引用,而 Message 中又持有 Handler 的引用,Handler 作为 Activity 的内部类 持有 Activity 引用。当 Activity 销毁时,因 MessageQueue 的 Message 无法释放,会导致 Activity 无法释放,引起内存泄漏。
子线程创建 Handler
应用启动时,系统会帮助我们创建 Looper。在子线程中创建 Handler 需要手动调用 Looper.prepare() 和 Looper.loop() 方法。
当子线程消息队列无消息时,结束时需要手动调用 Looper.quit() 或 Looper.quitSafely() 来终止 Looper,否则子线程会卡死在阻塞状态不能停止。
new Thread(){
@Override
public void run() {
Looper.prepare();
Handler handler = new Handler();
...
Looper.loop();
}
}.start();
Looper 死循环
Looper 死循环,没消息会进行休眠不会卡死,调用 linux 底层的 epoll 机制实现;应用卡死时是 ANR 导致的。