深入源码理解Handler机制

前言

  Handler机制老生常谈 也是面试必考 最近公司也在面试 发现很多人第三库都会用 比如熟练运用okhttp,rxjava 但是偏偏Android里面很重要的Handler机制却说的模棱两可,虽说代码很多 但是流程并不复杂 这次让我们站在源码的角度去理解并掌握它

概念 

  Handler机制:主线程和子线程的通信机制 多用在子线程发送消息通知UI线程更新UI
  Looper:轮询器 AndroidThread中启动 死循环 一直存在 直到进程销毁
  MessageQueue:Looper的成员变量 消息队列 链表结构
  Message:MessageQueue的成员变量 一个消息实体类

流程分析

  既然说Handler用于在主线程和子线程传递消息的 这里我们要把握一个关键点->消息队列 有队列就有入队和出队 自然构成了handler收发消息的整个流程,先来看看源码方法的大概调用过程
   这里写图片描述
  

  1. handler的sendMessage方法发出消息 通过 queue.enqueue方法进入MessageQueue(消息队列)
  2. Looper的loop方法不停的从MessageQueue里取消息
  3. 没消息就阻塞 有消息的话Looper就会调用Message的handler对象的dispathchMessage方法转发消息
  4. 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代码有更深入的研究..

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值