简书链接:handler的dispatchMessage方法是如何被调用的探索mtarget是如何被附加上handler的 文章字数:1036,阅读全文大约需要4分钟 首先来点基础描述: 主线程的handler的looper,也就是Loop.getMainLooper()
返回的loop,默认在ActivityThread
类的main
方法初始化了 ,在main方法里面调用了Loop.perpareMainLoper();
初始化了一个loop,所以一般主线程的looper
实际上就是那里初始化的looper 具体
ActivityThread类的
main```代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public static void main(String[] args) { CloseGuard.setEnabled(false); Environment.initForCurrentUser(); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } }
创建了一个默认的loop又维护了一个messageQuare
主线程的looper轮训方法loop()是早早就被调用了的,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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; Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { return; } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { } msg.recycleUnchecked(); } }
那么handler类里面的dispatchMessage
触发是因为添加到消息队列中的消息Message
类的``target被设置了handler,然后在
Looper类的
loop方法里面处理这个消息的时候触发,也就是下面的这句代码
msg.target.dispatchMessage(msg);```
1 2 3 4 5 6 7 8 try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } }
1 2 3 4 5 Looper相关方法 构建loop静态对象 保证一个线程只有一个
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));
}
1 2 至于```Looper.loop()```方法上面已经贴过了,也就是开启轮训,当没有的时候cpu进入等待。这个和某个**酷Q机器人**易语言源码当中的消息处理惊人的相似。他那个差不多就是消息队列的死循环,没有的时候就进行睡眠,然后有消息的时候线程唤醒。 里面用到了```ThreadLocal```通过线程名作为键,保证了一个线程只有一个```ThreadLocal```一个```Looper```
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
1 2 3 4 5 6 源码太深,这里只讲如何被设置上去的, 根据handler的源码分析,```post``` ```postDelay```实际上都最终调用了```sendMessageAtTime```然后调用了 ``` return enqueueMessage(queue, msg, uptimeMillis);``` 那么继续,先看看handler的一些方法,
public final Message obtainMessage()
{
return Message.obtain(this);
}
public final Message obtainMessage(int what)
{
return Message.obtain(this, what);
}
public final Message obtainMessage(int what, Object obj)
{
return Message.obtain(this, what, obj);
}
1 2 这里都把```handler```传递进去了 ```Message```的obtain方法设置了 ```m.target```
public static Message obtain(Handler h, int what, Object obj) { Message m = obtain(); m.target = h; m.what = what; m.obj = obj;
return m;
}
1 既然是这样的,那么自己创建一个纯message类会触发吗?
Message message=new Message(); message.what=1; message.obj=”测试纯message”; handler.sendMessage(message);
1 2 3 结果令人震惊,还是触发了,这```message.taget```他是如何被设置的呢? 然后又看了看,原来那报错的红色代码没有被我注意到,也就是说追踪走的```sendMessageAtTime```方法走的```enqueueMessage```方法中强制给message的targer设置了handler为自己。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
这句话明显的写这句话``` msg.target = this;``` 所以 明白为什么可以回调了,ok讲解完毕,知其然也知其所以然了。
### 其它相关
1、```handler```类的```queue```成员变量是从Looper中获取到的,handler发消息实际上是拿到```Looper```里面的静态消息队列字段
``` mLooper.mQueue```
2、而``` mQueue = new MessageQueue(quitAllowed);```也就是消息队列对象的初始化是通过```prepare```的调用导致``` sThreadLocal.set(new Looper(quitAllowed));```这句代码被执行,然后导致```Looper```构造方法执行,然后触发这个队列的初始化。···``` mQueue = new MessageQueue(quitAllowed);```···
```sThreadLocal```也就是```ThreadLocal```默认在成员变量就初始化了```sThreadLocal```而且是静态的 这个字段也是放到```Looper```类里面存起来的
3、真正负责处理消息的是在```looper()```开启一个死循环for,不断的0调用```MessageQueue```的```next()``` 知道返回null才终止,,在这个方法几乎是没法出来了,永远卡在这个方法,除非满足特定条件,`比如```messagequare```的```quit```方法被调用。
4、```looper```的```looper```死死循环外,消息队列```MessageQueue``` ```next```也嵌套了一个死循环,所以即使消息没有也不会进行立马返回,而是等待,只有当有消息的时候才返回给```looper()```处理这里面主要做一些时间的处理,比如那些延时时间发送的。
有些东西还是没法理解,深度对我来说还是遥不可及