基础概念
- Handler 消息的发送者和接收者
- Message 消息的载体
- MessageQueue 消息链表按照when的时间进行插入
- Looper 泵站从MessageQueue中提取消息
Handler
带着问题读源码
- message 消息接收的优先级
- 异步消息怎么创建
- 接收消息的优先级
构造方法
首先看构造方法, 构造方法最终有2种,可以说一种是传入Looper的 一种是不传入Looper的
2种的差异就是 是否要来自己获取Looper。(难道这种不能通过重载来实现吗)
小知识点:
- 一个线程只有一个 Looper 和一个MessageQueue,但是可以有多个Handle。
- Message是通过target来找到指定Hander 进行回调的
第一种:
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;
}
/**
* @param looper 线程切换的关键,一个线程中只有一个,并且只能初始化一次
* @param callback Message的回调,这个只能从构造方法中传入
* @param async 是否是异步消息。 在队列中异步消息有更高的优先级
*/
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
发送消息
发送消息最终都会调用sendMessageAtTime,time是 SystemClock#uptimeMillis 开机之后的时间 time 也是插入队列的依据
第一种
/**
* @param r 回调的Runnable 这个最终指定的是 Message.callback
* @param token 这个是用来取消时候用的 removeCallbacksAndMessages
* @param uptimeMillis time 距离开机之后多久
postAtTime(@NonNull Runnable r, @Nullable Object token, long uptimeMillis)
第二种
/**
* @param msg 要发送的消息
* @param uptimeMillis 距离开机之后多久用来队列排队
sendMessageAtTime(@NonNull Message msg, long uptimeMillis)
第三种
放在队列首部的消息,这个里面也就是把 uptimeMillis 设置为 uptimeMillis 为0
postAtFrontOfQueue(Runnable r)
sendMessageAtFrontOfQueue(Message msg)
接收消息
优先级:
- Message 自带的callback,callback的来源:post(Runnable r) 中的 Runnable
- mCallback 构造方法中传入的mCallback
- Handler 方法 handleMessage
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
入队
这里只有一个关键的地方,就是经常说的Handler为什么会引起来内存泄漏的原因
msg.target = this; 这里让Message持有了Handler对象。
但是Message是会被丢到了队列中。那么当Activity退出后Message依然还在队列中时就会引起内存泄漏。
原因:当系统GC的时候,因为 Handler有对Activity引用,Message又引用了Handler。那么系统就不会对Activity 进行回收了
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);
}
Message
一个的单链表模式,通过next来获取下一个Message。而 MessageQueue 并不是消息队列而是处理消息队列的工具
这里大多为实体类唯一可以说的是缓存应用
写入缓存
void recycleUnchecked() {
// Clear out all other details.
......
......
synchronized (sPoolSync) {
// 如果没有达到最大值 MAX_POOL_SIZE 的值为50
if (sPoolSize < MAX_POOL_SIZE) {
// sPool 是一个Message对象
// 这个把当前消息放在链表的首部
// 第一个操作把当前的sPools放入next节点
next = sPool;
// 第二个操作把首节点指向首部
sPool = this;
sPoolSize++;
}
}
}
获取缓存消息
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;
}
}
// 如果没有缓存那么直接使用Message
return new Message();
}
MessageQueue
MessageQueue其实并不是一个消息队列。他只是Message链表的处理的一个类 这个里面主要有2块 1. Message 入队 2. 取消息
入队
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;
// 第一种情况直接加入到 当排头加入到队列首部
// 1. p == null 也就是当前没有消息列表
// 2. when == 0 加入到队列首部,在Handler中说过 postAtFrontOfQueue(Runnable r) sendMessageAtFrontOfQueue(Message msg) 这2种方式 when为0
// 3. 当前消息的When是小于 目前队首的When
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循环来插入链表
// 确认位置的2个点
// 1. 如果没有子节点 那么认为已经是在队尾 直接插入即可
// 2. 当前的时间小于下一个节点的时间
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 手拉手把前后2个节点给拉起来
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
// 是否需要进行唤醒 线程等待需要就看 mBlocked, 这里会在取消息的时候进行赋值
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
获取消息
Message next() {
......
......
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// 线程阻塞,如果nextPollTimeoutMillis == -1 会一直等待,如果nextPollTimeoutMillis > 0 等待多少毫秒
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;
// target 为null的时候是一个消息屏障(这个是系统可用,APP层不可用)
// 这里是主要优先处理紧急消息
// 这里的意思是 如果当前是首部消息为屏障消息 那么就先从队列中获取其中的异步消息进行处理
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());
}
// 如果有当前消息则进行消息处理
if (msg != null) {
// 如果当前第一个消息的时间比当前时间晚 那么就进行等待
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 {
// 获取到了一个消息,那么就不需要进行 blocked
mBlocked = false;
// prevMsg != null ,这个什么时候回出现呢?
// 只有当获取到屏障消息时 prevMsg 才会不为null
if (prevMsg != null) {
// 重新吧prevMsg放回到链表中
prevMsg.next = msg.next;
} else {
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;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
// 如果 没有IdleHandler 那么线程就需要等待
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// IdleHandler 回调,以及是否 需要keep,如果不需要就remove掉
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);
}
}
}
}
}
Looper
Looper 是Handler消息处理的泵站,他的主要作用是不断的通过MessageQueue中取出消息,并交个Handler来处理消息。Looper是通过ThreadLocal来进行线程切换的。
初始
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");
}
// 创建了一个Looper对象放入到ThreadLocal
sThreadLocal.set(new Looper(quitAllowed));
}
开始循环
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;
......
......
for (;;) {
// 通过MessageQueue的next()方法来获取Message
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......
......
try {
// 把消息丢给 Handler.dispatchMessage 处理消息
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
......
throw exception;
} finally {
......
}
......
......
// 消息进行回收并入缓存
msg.recycleUnchecked();
}
}