在具体看源码之前,我已经知道了MyMessage中有一个成员变量Handler target来保存handle,于是我写一个简易模拟程序。
考虑因素如下:
1、应用程序无论是哪个MyHandler sendMessage过来的,都可以用一个looper进行处理。
2、MyLooper要有不断提取消息和处理消息的能力,那么要继承Thread。使用一个List list来存储消息,run方法不断取和获取MyMessage中的target,调用handlerMessage方法即可。
类图大概是这样的:
当你想强行加一些prepare、loop等函数的时候,你会觉得很鸡肋。
而且考虑到多线程虽然用同一个MyLooper可行,但是每个线程的生命周期和处理的时间不一,不应该采用一个MyLooper对象。带着一些疑问我们看看源码是怎么写的。
1、Handler如何获取Looper中的消息队列
默认构造函数调用this(null, false);
Handler.java
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;
}
Looper.myLooper();是获取当前线程的Looper对象,此对象有成员mQueue。
handle算了与消息队列联系起来了,方法sendMessage调用了enqueueMessage,将消息放去队列
Handler.java
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
...
return queue.enqueueMessage(msg, uptimeMillis);
}
2、那Looper是怎么跟当前线程形成一对一关系的
Looper.java
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));
}
可见prepare就是为了创建Looper,然后与当前线程绑定。
Looper类中成员变量static final ThreadLocal sThreadLocal = new ThreadLocal(); 保存着线程和对应looper对象。
之前handle构造函数的Looper.myLooper();语句,其实是
public static Looper myLooper() {
return sThreadLocal.get();
}
sThreadLocal.get(); 返回当前线程looper对象。
3、所以Looper中loop方法先要获取当前线程looper对象,然后得其消息队列。
public static void loop() {
final Looper me = myLooper();
...
for (;;) {
Message msg = queue.next(); // might block
...
msg.target.dispatchMessage(msg);
...
msg.recycle();
}
}
4、Handle消息处理顺序
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
先msg的回调方法,再就是handle自身回调方法,最后是handleMessage方法.
自此我们了解了Looper Handle机制”是什么”,但更值得思考的是”为什么”。
5、一对一的对应关系可以采用组合的方式实现,即线程里面有Looper成员变量,应思考设计中的高内聚低耦合