至尊宝是真真的爱着紫霞仙子。 -- 题记
先看下测试代码:
从上图可知mHandler是在onCreate的主线程执行的;mInnerHandler是在子线程执行的;
1、从handler的源码角度看看handler是如何执行的
1. 从handler的构造器可知,每新建一个Handler对象会重新生成一个looper对象;通过mLooper会生成一个消息池MessageQueue;也就是说一个Handler对象对应一个Looper对象,一个Looper对应一个消息池;
1.1 那么myLooper方法是如何生成Looper的呢?
ThreadLocal 源码注释中有很清楚的解释:它是线程的局部变量,这些变量只能在这个线程内被读写,在其他线程内是无法访问的。get方法 是ThreadLocal 里的一个方法,
从当前线程获取map,从map里获取Looper;;
截下来看下getMap()方法是怎么获取到ThreadLocalMap的
他是Thread线程里的一个方法,这里说明了在哪个线程里创建的handler对象,handlerMessage就在哪个线程;一个线程只有一个Looper、只有一个MessageQueen,只有一个只供当前线程使用的ThreadLocal ;
ThreadLocal 有get()方法,那么他也一定要set方法;
这回知道为什么在线程里new Handler对象要调用Looper.prepare()了吧;
2.为什么在OnCreate里,没有调用Looper.prepare ?
我们看下ActivityThread这个类
他这里已经调用了,启用的是主线程;这里还是是main方法,Activity的OnCreate还没有被调用,原因下次再说;
截下来我们看下 Looper.loop()方法;
所以loop方法的调用肯定都是在一个方法的最后,因为这是一个死循环,执行这个方法就不再执行下边的任何步骤了;
当前线程的Looper从消息队列读取消息,当读完所有消息时,进入睡眠,线程阻塞。线程往消息队列发送消息,并且往管道文件写数据,线程即被唤醒,从管道文件读取数据,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。
那么他是怎么往消息队列里添加消息的呢?
通过 mHandler.sendEmptyMessage(1);这类的方法,通过mHandler.sendxxxxxMessage源码我们可知道,他们最终调用的都是sendMessageAtTime方法
这里最终调用的是消息池的enqueueMessage方法,将消息添加到队列,根据message对象的when的值将消息排队,然后唤醒当前线程继续轮询;
Looper.loop()方法里的for死循环里将消息分发出去
msg.target.dispatchMessage中的target点进去其实就是Handler对象,它调用自己的HandleMessage方法将其回调出去
总结
if ( 从onCreate里new Handler){
在ActivityThread的main()方法中存入了Looper.prepareMainLooper();(这里已经创建了Looper,messagequeue)
} else {
每次在新的线程创建Handler对象 需要调用Looper.prepare();逻辑执行完还要调用Looper.loop();去启动消息池的轮询;
}
new Handler的时候Handler就已经拿到了线程的Looper 。MessagQueue
handler发送消息:
把Handler保存到Message里。
把Message保存到messageQueue里。
然后不断地执行获取消息的方法:Looper.loop();去出message,然后调用handler的dispatchMessage(msg),消息回调到当前handler的handleMessage里;