主要思想
- 通过MessageQueqe保存mesage
- 通过looper轮询MessageQueqe
- handler回调处理message
开始看源码喽~
创建Handler
1
2
3
4
5
6
7
8
9public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
}构造函数中,赋值了三个重要的对象 Looper、消息队列mQueue、和一个可选的callback。重点关注Looper
1
2
3public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}从ThreadLocal里面取出一个Looper,如果没有会在Handler构造函数中报错。这就是为什么在新的新的线程中创建Handler,要调用Looper.prepare和Looper.loop()方法,这两个方法会初始化Looper.UI线程需要的原因是,在应用启动时候,已经做了初始化Looper的操作。
Looper初始化
从Looper的prepare函数中看起
1
2
3private static void prepare(boolean quitAllowed) {
sThreadLocal.set(new Looper(quitAllowed));
}创建了一个Looper,并放到当前线程的ThreadLocal中去。继续看构造函数
1
2
3
4private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}创建了一个消息队列并持有了当前线程的引用。接着看Looper的loop()函数
1
2
3
4
5
6
7
8
9
10
11
12
13public static void loop() {
//myLooper返回的是sThreadLocal.get()
final Looper me = myLooper();
MessageQueue queue = me.mQueue;
//轮询消息队列
for (;;) {
Message msg = queue.next(); // might block
//调用handler的dispatchMessage方法。
msg.target.dispatchMessage(msg);
//回收复用
msg.recycleUnchecked();
}
}函数很简单,不断轮询looper上的消息队列,当拿到一个message时,找到message对应的handler,调用handler的dispatchMessage方法,处理message.
Handler会造成内存泄漏的原因
注意第7行函数,message 强引用了handler。
这也是为什么在Activity中创建Handler的非静态内部类会造成内存泄漏的原因:
由于非静态内部类会持有外部类的引用,形成一个引用链,message->handler->activity。
而mesage在队列中,回收时机不确定,GC准备回收Activity时,发现还在被message间接引用,不再回收Activity对象.
通常Activity中有着大量的对象,无法回收Activity导致这些对象也无法回收,形成严重的内存泄漏。
建议使用弱应用,或者使用MVP等模式解耦ActivityHandler分发Message
先看dispatchMessage方法
1
2
3
4
5
6
7
8
9
10
11
12public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}处理message有三条路。
1). 若msg存在callBack,则使用msg上的callback
2). 否则检查handler上的mCallback(默认为空),不为空则使用mCallback的方法
3). 最后调用我们熟知的handler上的handleMessage方法。注意第二点,利用这个特性,可以干很多事。比如DroidPlugin hook了 ActivityThrad上的mH类,用与Activity的插件化
Handler 发送message
handler初始化和分发消息的逻辑已经分析完毕,接下来看最后一部分-发送消息的路径.
sendMessage方法
1
2
3public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}最终会调用到sendMessageAtTime方法
mesage加入到MessageQueue中
1
2
3
4public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
return enqueueMessage(queue, msg, uptimeMillis);
}函数将message加入到messageQueue中,看下加入队列的实现
入队实现
1
2
3
4
5
6
7
8/** MessageQueue **/
boolean enqueueMessage(Message msg, long when) {
//单链表+1的操作
Message p = mMessages;
msg.next = p;
mMessages = msg;
//...
}很简单,就是加个message加到队列的末尾。在回想之前Looper轮询msgQueqe的操作,整个流程都清晰了。