前言
Handler机制老生常谈 也是面试必考 最近公司也在面试 发现很多人第三库都会用 比如熟练运用okhttp,rxjava 但是偏偏Android里面很重要的Handler机制却说的模棱两可,虽说代码很多 但是流程并不复杂 这次让我们站在源码的角度去理解并掌握它
概念
Handler机制:主线程和子线程的通信机制 多用在子线程发送消息通知UI线程更新UI
Looper:轮询器 AndroidThread中启动 死循环 一直存在 直到进程销毁
MessageQueue:Looper的成员变量 消息队列 链表结构
Message:MessageQueue的成员变量 一个消息实体类
流程分析
既然说Handler用于在主线程和子线程传递消息的 这里我们要把握一个关键点->消息队列 有队列就有入队和出队 自然构成了handler收发消息的整个流程,先来看看源码方法的大概调用过程
- handler的sendMessage方法发出消息 通过 queue.enqueue方法进入MessageQueue(消息队列)
- Looper的loop方法不停的从MessageQueue里取消息
- 没消息就阻塞 有消息的话Looper就会调用Message的handler对象的dispathchMessage方法转发消息
- dispathchMessage方法里面实际调用的handleMessage回调
源码实现
Handler
首先是入口方法handler.sendMessage
分析:最终会调用queue.enqueueMessage方法 queue就是MessageQueue(消息队列)
这里的queue是怎么来的呢? 看看Handler的构造函数
分析:实际上是Handler初始化的时候就赋了值,queue是Looper里面的 而mLooper = Looper.myLooper 下面去Looper里面看看这个方法
Looper
分析: Looper构造函数里面初始化了MessageQueue,以及当前线程 myLooper方法这里的sThreadLocal是什么呢?再看
原来是Looper持有一个静态的本地线程(ThreadLocal) 它是java为解决多线程并发所提供的一种方法。简单说就是数据隔离
用在这里的意义在于->我们可能会有另一个主线程(有别于UI线程)收发消息 多个主线程应该持有自己的Looper对象 保证每个线程的数据隔离 互不干扰
深入理解可以看http://blog.csdn.net/lufeng20/article/details/24314381
问题又来了,我们知道获取Looper对象是sTreadLocal.get() 也就是本地线程中取出来的,那么是什么时候放进去的呢?也就是说Looper是什么开始构建出来 并工作的呢?
我知道没有Looper轮询器取消息 handler可以发消息 但绝b收不到消息 所以我们可以想的到 Looper很有可能是在UI进程一启动 就创建了 我们去Android入口看看:
AndroidThread
分析:到这里我们可以感到欣慰了,如果没有猜错的话 Looper.prepareMainLooper();就是构建Looper对象的方法
Looper
果然是这样的 UI线程会创建一个Looper对象 并set到TreadLocal里面 我们注意到prepare(false) UI线程这里传的是false 而其他线程默认是true 看下它是在那用到的 找到MessageQueue里面的quit方法
MessageQueue
分析: MessageQueue里面的quit 意思是消息没有处理完 主动退出 而主线程是不予许你这样操作的 所以传的false
大致的我们都清楚了 最后看下Looper.loop()
总结
最后我们再把流程梳理一遍
AndroidTread ->Looper.prepareMainLooper() -> Looper.loop()
1. AndroidThread创建一个UI线程的Looper对象并set到ThreadLocal在Looper的构造函数里会初始化当前MessageQueue对象和当前线程
2. handler.sendMessage最终调用当前Looper的MessageQueue对象的enqueueMessage方法将消息压入消息队列(MessageQueue)
3. Looper的loop方法先从ThreadLocal 取出当前线程的Looper对象,得到当前Looper对象的MessageQueue然后轮询调用MessageQueue的next方法取消息
4. 如果有Message就调用这个Message的handler对象的dispatchMessage方法转发消息
5. 最后在handleMessage回调接受消息
子线程里面怎么用Handler接收消息?
看到这里我们知道 每个线程都有一个Looper对象去轮询MessageQueue里面的消息 然后转发给handler接收 UI线程在AndroidThread里面帮我们写好了创建Looper以及Looper.loop的方法 那么如果要在子线程中使用Handler 我们就需要手动创建 其实源码注释已经给了解释
Android还给我们提供了HandlerThread这样一个类 也是这种实现方式
最后
handler.sendMessage的时候 不是直接new Message而是用的 Message.obtain(),它的内部是一个缓存池 可以避免频繁创建对象 节省内存
另外,MessageQueue enqueueMessage入队方法 以及 next出队方法的实现 这些涉及到链表数据结构
我这里主要分析了java层的代码 源码里面还用到很多native的方法 这些需要我们对Android底层C代码有更深入的研究..