老生常谈
Handler 消息发送和接收者
Message 消息实体
MessageQueue 消息队列,存储消息,内部实现是链表
Looper 从MessageQueue取消息,交给handler处理
要开启消息循环必须调用Looper的prepare()和loop()方法,主线程的消息循环是在应用程序入口ActivityThread中默认开启的
//ActivityThread
public final class ActivityThread {
...
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
}
}
//Looper
public final class Looper {
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));
}
}
在main()方法中调用了prepareMainLooper(),prepareMainLooper又调用了prepare(false)方法创建了不允许结束的MessageQueue,同时用ThreadLocal绑定当前线程和Looper。
为了实现线程安全,各个线程内的变量独立,空间换时间
Looper存储方式大概是这样:Looper中有个静态变量sThreadLocal,调用set方法获取到当前线程的ThreadLocalMap,把当前ThreadLocal和值传入(即sThreadLocal和looper对象),最后保存在Entry数组中,Entry是key和value的封装类,对key是弱应用。这样,虽然ThreadLocal是同一个(key相同),但是因为线程不同,保存的map也不同,在不同线程里调用会有不同的值,线程之间互不影响。
prepare()用来创建MessageQueue和looper,和loop()用来从MessageQueue中读取消息,实现循环。
public final class Looper {
...
public static void loop() {
...
//死循环,不让程序执行完毕
for (;;) {
//从消息队列中取消息,线程可能阻塞
Message msg = queue.next(); // might block
...
try {
//消息处理
msg.target.dispatchMessage(msg);
} finally {
...
}
//消息对象重复使用,防止频繁创建消息对象
msg.recycleUnchecked();
}
}
}
取消息
public final class MessageQueue {
Message next() {
...
//IdleHandler的个数
int pendingIdleHandlerCount = -1; // -1 only during first iteration
//下次唤醒时间
int nextPollTimeoutMillis = 0;
for (;;) {
//linux的epoll机制,实现阻塞
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;
//todo 同步消息屏障
...
if (msg != null) {
if (now < msg.when) {
//消息还未到处理时间,计算下次唤醒时间nextPollTimeoutMillis
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
//消息可处理
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 {
//消息为空,无限期阻塞,等待被唤醒
nextPollTimeoutMillis = -1;
}
}
}
}
next()同样是个死循环,取到消息就返回,否则阻塞。阻塞时间nextPollTimeoutMillis有三种取值:
public final class MessageQueue {
Message next() {
...
for (;;) {
...
synchronized (this) {
//msg的target为空的情况
if (msg != null && msg.target == null) {
//取异步消息,取不到异步消息时msg为空
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
}
}
}
}
当队列头第一个消息的target为空时,说明是同步屏障消息,跳过同步消息去取异步消息。若取不到,则无限期阻塞等待唤醒。
同步屏障是一种优先级机制,目的是为了处理某些优先级较高的消息,比如绘制。
IdleHandler可以在handler空闲时被执行,具体如下
public final class MessageQueue {
Message next() {
...
for (;;) {
...
synchronized (this) {
...
//当消息队列为空或者没有要立即处理的消息时,会处理IdleHandler
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
//没有idle handler,阻塞等待唤醒
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
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 {
//IdleHandler的返回值用来判断是否保留
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
//false表示只执行一次
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
//执行完IdleHandler之后可能有新消息到来,因此不阻塞,立刻尝试获取消息
nextPollTimeoutMillis = 0;
}
}
}
IdleHandler只有在MessageQueue.next()循环首次迭代,且当消息队列为空或者消息不需要立即处理时会执行,执行完后此次循环不再调用,等待Looper再次调用MessageQueue.next()。
sendMessage()和post(runnable)相关方法都是用来发送消息,不同之处在于post()方法会把runnable赋值给自身的callback
public class Handler {
...
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
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;
...
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
//msg的target会引用handler
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
}
入队前会让消息的target指向调用者本身,即Handler。最终调用MessageQueue.enqueueMessage()方法进入消息队列。
public final class MessageQueue {
...
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) {
//队列为空或当前入队的消息比队头的消息延迟时间短,需要唤醒队列立刻执行
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;
}
}
当消息入队时,会按照消息的延迟时间从小到大排序,排在前面的消息先执行。因为MessageQueue.next()可能导致阻塞,enqueueMessage()则会唤醒,让消息继续循环。
looper中拿到消息后会调用msg.target.dispatchMessage()方法处理消息.
public final class Looper {
...
public static void loop() {
...
for (;;) {
...
try {
//消息处理
msg.target.dispatchMessage(msg);
} finally {
...
}
//消息对象重复使用,防止频繁创建消息对象
msg.recycleUnchecked();
}
}
}
msg.target即发送该msg的Handler对象。
public class Handler {
...
/**
* Handle system messages here.
*/
public void dispatchMessage(@NonNull Message msg) {
//通过post的方法发送,则执行
if (msg.callback != null) {
handleCallback(msg);
} else {
//否则先执行全局的callback
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//再调用子类重写的handleMessage方法
handleMessage(msg);
}
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(@NonNull Message msg) {
}
}
最终回到handler中执行。因此虽然从子线程发消息,但是调用handleMessage方法的是在主线程中的looper.next()方法,实现了子线程到主线程的切换。
public class Handler {
...
public final void removeMessages(int what, @Nullable Object object) {
mQueue.removeMessages(this, what, object);
}
}
//MessageQueue
public final class MessageQueue {
void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
//处理表头的消息
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
//处理表内的消息
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
}
该方法会调用到MessageQueue的removeMessages方法,该方法会删除MessageQueue里的what和object匹配的消息,如果object为空,则删除所有what匹配的消息。删除的前提是msg.target == handler,即相同的what,不同的target会被当做不同的消息,也就是说两个Handler之间的消息互不影响。
消息循环的引用链为:
Handler作为内部类持有外部类Activity的引用,Message的target又持有Handler的引用,当Activity关闭时Message间接引用Activity导致内存泄漏。
1、Handler改为静态内部类,以弱应用的方式引用Activity
2、删除所有消息
前面分析removeMessages()方法会删除MessageQueue中所有延迟消息,删除时会调用Message.recycleUnchecked()方法。
public class Message{
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
}
该方法会把target置空,即