看源码首先固然是从使用处看起,咱们首先来看一下平时项目中handler的使用,咱们首先定义了一个handler对象,而且写好了接收到消息之后须要执行的操做,而后在子线程中发送一个消息。面试
问题一 handler发送的消息是怎么到达handlerMessage回调的呢?
数据结构
首先咱们就从源头开始看起,handler.senMessage()方法一路点下去,发现最终调用的是MessageQueue类的enqueueMessage方法,也就是说最终是把message添加到了消息队列MessageQueue中,以下图所示app
OK,消息放进去了,可是咱们发现这里面并无调用handler的handleMessage方法,因此咱们换个角度想,放进去了总要取出来吧,否则放进去就没有意义了。因而咱们就在MessageQueue中寻找返回值为Message的方法,果不其然找到了一个next方法,在该方法中返回了刚刚保存好的message,以下图函数
那么问题又来了,到底是谁调用了这个next方法把消息取出来了呢?解决这个问题就要反过来考虑,须要调用next方法就须要实例化MessageQueue这个类,否则无法调用,MessageQueue是在Looper中初始化的,因此接下来咱们来看看Looper类的源码。在Looper源码中是在构造函数中初始化MessageQueue的oop
接下来咱们再搜一下调用next方法的地方
spa
咱们发如今Looper的loop方法中有一个无限循环,其中每次循环都调用MessageQueue的next方法,若是找到了就会执行msg.target.dispatchMessage(msg),那么msg.target是什么东西呢?咱们接下来就点开Message类,查看一下target属性,以下线程
哇塞,原来是Handler对象,这里其实就是调用的handler的handlerMessage方法,如今逻辑就清晰了。Handler首先将咱们发送的message保存到MessageQueue,而后Looper获取到message之后调用Handler的handlerMessage方法将message返回。3d
问题二 Handler是如何实现跨线程通讯的?指针
纵览全局,咱们发现,其实message至关于一个物品,MessageQueue至关于一个仓库,被handler放到MesageQueue,而后被Looper取出来还给handler,对于物品来讲是不会挑选主人的,类的属性也同样,不管哪一个线程均可以操做修改。因此message在子线程被放进去之后在主线程被取出来就很正常了。
cdn
问题三 Looper是在哪里被调用的?
咱们平时使用Handler通常是子线程和主线程通讯,而主线程的Looper其实在app初始化的时候就已经初始化而且开始Loop无限循环获取Message了,具体代码在ActivityThread的main方法中,其中prepareMainLooper就是初始化Looper,而后还调用了loop方法。以下图
问题四 如何保证Looper惟一性,一个线程不会出现多个Looper?
咱们都知道,若是同一线程每次都new一个Looper的话就没办法保持惟一性。想要知道这个知识点,必须看一下Looper是怎么设置和获取的,咱们点进去初始化的源码,以下图
咱们发现,Looper的设置和获取并非普通的属性get和set,而是经过ThreadLocal类来操做,因此咱们点进去ThreadLocal看一下,发现里面Looper的设置和获取操做都须要传入线程参数,也就是说以线程为Key,对应了惟一的Looper,其实Looper惟一也就意味着MessageQueue也是惟一的,由于MessageQueue是在Looper构造方法里初始化一次的,可是Handler能够有多个,由于咱们每初始化一个Handler对象,都会被Message记录,最后调用相应Handler的handleMessage方法,并不会有冲突。其中ThreadLocal代码以下
问题五 MessageQueue是一个什么样的数据结构?
分析这个问题,咱们首先要找到其设置数据的地方,以下图所示,MessageQueue保存了每条message的值和next指针,也就是说想获取到下一条消息必需要看上一条消息的next指向,这样就致使了数据的先进先出,和LinkedList的实现相似,显然是一个单向链表的实现。
问题六 消息是怎么实现延时的?
1.既然消息是保存在队列中,那么刚保存的时候就应该保存好该消息所在的位置才对,否则在获取的时候就没办法保证延时短的消息先发送了,如问题五中的图,这个的实现其实就是死循环对每一个message的延时时间进行对比,若是当前消息的延时短则更改指针指向,将当前消息插入到队列中。
2.若是发送消息的时间没到,则不交给Looper。以下图,在Looper获取消息时会对时间进行判断,若是时间还没到则不返回message,即至关于本次循环并无到达时间须要发送的消息
问题七 Handler机制中生产者和消费者模式体如今哪里?
前面说到handler中把消息放到了messageQueue,而后Looper从messageQueue中获取消息并使用,这个至关于就是一个生产者和消费者模式,一个负责生产一个负责消费。生产消费者模式中的阻塞在handler中也是体现得淋漓尽致,在获取消息时,若是消息池中消息数量为空,那么此时进入阻塞状态,以下图
问题八 为什么Looper中死循环不会阻塞UI
首先咱们必须明白的是app自己就是一个死循环,否则岂不是一打开就结束了?其次Looper和更新UI是共存的关系,这里会有一个底层的睡眠机制,在须要的时候再唤起。
最后:本人小萌新,以前都是看得多写得少,如今也想把本身的所见所得记录下来给你们分享分享,如有写错或者没有补充完整的地方欢迎各位大神指教,之后有新的心得体会会及时更新本文,谢谢你们阅读!