Handler从源码角度分析实现原理

2021-01-11  本文已影响0人  一束佛光

至尊宝是真真的爱着紫霞仙子。  -- 题记

先看下测试代码:

从上图可知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里;

上一篇下一篇

猜你喜欢

热点阅读