Android Handler 机制实现原理分析
作者:sun_month 发布时间:2022-01-14 23:46:49
handler在安卓开发中是必须掌握的技术,但是很多人都是停留在使用阶段。使用起来很简单,就两个步骤,在主线程重写handler的handleMessage( )方法,在工作线程发送消息。但是,有没有人想过这种技术是怎么实现的呢?下面我们一起探讨下。
先上图,让大家好理解下handler机制:
handler机制示例图
上面一共出现了几种类,ActivityThread,Handler,MessageQueue,Looper,msg(Message),对这些类作简要介绍:
ActivityThread:程序的启动入口,为什么要介绍这个类,是因为该类就是我们说的主线程,它对Looper进行操作的。
Handler:字面意思是操控者,该类有比较重要的地方,就是通过handler来发送消息(sendMessage)到MessageQueue和 操作控件的更新(handleMessage)。handler下面持有这MessageQueue和Looper的对象。
MessageQueue:字面意思是消息队列,就是封装Message类。对Message进行插入和取出操作。
Message:这个类是封装消息体并被发送到MessageQueue中的,给类是通过链表实现的,其好处方便MessageQueue的插入和取出操作。还有一些字段是(int what,Object obj,int arg1,int arg2)。what是用户定义的消息和代码,以便接收者(handler)知道这个是关于什么的。obj是用来传输任意对象的,arg1和arg2是用来传递一些简单的整数类型的。
下面,我们按照启动顺序来进行源码分析:
从上面可以看出,ActivityThread类是用来启动Android的,其源码为:
ActivityThread类:
接下来,我们看到Looper类了,我们进去看看里面的源码实现:
首先,我们看看里面有哪些字段:
Looper的内部属性
然后我们迫不及待地要想去看看prepareMainLooper方法,到底干了什么
Looper.prepareMainLooper()方法
这里我们可以看到,prepareMainLooper是为了设置一个持有消息队列和消息序列器的Looper进去ThreadLocal。接下来我们看看loop方法吧:
Looper.loop()方法
我们可以看到loop方法中,会取出内部的消息序列器,并且迭代里面的消息,根据消息的target分发消息(到handleMessage方法中)。如果你有疑问,你应该是不清楚Looper的MessageQueue为什么会有Message。那么我们就马上去看,到底是哪里添加消息的。话说,到了这里我也好像没有分析到和我们handler相关的操作吧。因为你和我都知道handler的作用是sendMessage和handleMessage,所以我们知道,Looper中的消息序列器的消息体,肯定是从sendMessage中添加进去的。不墨迹,我们马上进入Handler的源码分析。
首先,我们先看看Handler的字段:
Handler的字段
接着,我们看看Handler的构造方法,我们可以看到,Handler有两类构造方法(别看到6个,它们都是往这两种方法调用的):
Handler的构造方法
接着,我们要进入Handler.dispatchMessage()方法,因为我们要解释上面刚刚Looper.loop方法。dispatchMessage的方法很简单,只有三个方向,其源码为:
Handler.dispatchMessage()方法
到这里为止,执行代码就结束了。那么问题来了,消息从哪里来的?带着这个疑问,我们马上进入Handler.sendMessage()逻辑去看看,其源码是:
Handler.sendMessage()方法
好不容易找到了发送消息的逻辑并理解了,但是还要去壳,在MessageQueue中分析了,首先,我们回顾下,消息序列器是在Looper.prepare()中初始化的。MessageQueue源码,构造方法很简单:
MessageQueue构造方法
然后我们再到达MessageQueue.enqueueMessage()方法中看源码:
MessageQueue.enqueueMessage()方法
这个是发送消息的最终执行代码,就是把消息放进消息序列器。在Looper.loop()方法中,我们是需要不断从消息序列器中取出消息的。其过程也是我们可以进去MessageQueue.next()的源码中看看:
MessageQueue.next()方法
这样,整个过程就完成了。在这些执行过程中,Message是它们的物件。我们可以看看Message的结构:
Message的字段
除此之外,Message的数据结构是基于链表的,方法都很简单的,我就不贴出来了。
总结一下,其实就是用一个ThreadLocal来存储对象,然后在执行的时候,能够保证对象的不变形,这样就能达到在主先线程更新UI了。


猜你喜欢
- Springmvc+hibernate成为现在很多人用的框架整合,最近自己也在学习摸索,由于我们在开发项目中很多项目都用到列表分页功能,在此
- 1.)添加引用 build.gradle 中添加配置 compile 'com.github.bumptech.glid
- 用户可以自定义打印某一年的年历,即:把某一年的日历全部打印出来如把2013年的年历打印出来如下:January 2013&nbs
- 本文实例为大家分享了Android实现背景图滑动变大松开回弹的具体代码,供大家参考,具体内容如下原图放大后1、自定义view继承Scroll
- 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口;Thread类是在java.lang包中定义的
- 一.背景最近业务需求需要导出Execl,最终做出的效果如下,中间牵扯到大量的数据计算。二.疑难问题分析问题1:跨单元格处理及边框设置问题2:
- 使用背景项目中用户频繁访问数据库会导致程序的卡顿,甚至堵塞。使用缓存可以有效的降低用户访问数据库的频次,有效的减少并发的压力。保护后端真实的
- 本次教程将教大家如何用monkeyrunner进行android的自动化测试,包括环境的搭建、monkeyrunner和uiautomato
- 最近在开发即时通讯这个模块的时候使用到了自定义的相机,需求与微信一样,要求相机能长按和轻点,当时在网上找自定义相机的资源,很少,所以,我在这
- 详解json string转换为java bean及实例代码pom中添加如下两个库:<dependency> <
- 1. RSA加密与解密 -- 使用公钥加密、私钥解密public class RSATool { &nb
- 本文将基于Spring Boot介绍两种生成二维码的实现方式,一种是基于Google开发工具包,另一种是基于Hutool来实现;
- 项目需求中有个功能模块需要用到时间选择控件,但是android系统自带的太丑了,只能自己优化下,结合WheelView实现滚轮选择日期,好像
- 什么是委托?之前写了事件的介绍:https://www.jb51.net/article/59461.htm这里也把委托相关知识也总结一下。
- 前言在一个 Web 请求中,参数我们无非就是放在地址栏或者请求体中,个别请求可能放在请求头中。放在地址栏中,我们可以通过如下方式获取参数:S
- Android 关闭多个Activity的实现方法总的来说有四种方法:1、使用Application来进行关闭public class Ap
- 1、python的每一个语句的后面可以添加分号也可以不添加分号;在一行有多条语句的时候,必须使用分号加以区分2、查看Python版本号,在D
- 前言想使用ffmpeg打开摄像头,需要输入摄像头的名称,而ffmpeg本身的枚举摄像头列表功能不是接口,所以需要用其他方式获取到设备列表。C
- 前言spring框架作为JavaEE框架领域的一款重要的开源框架,在企业应用开发中有着很重要的作用,同时Spring框架及其子框架很多,所以
- 本实例实现在jsp页面实现查询全国城市天气预报的功能,供大家参考,具体内容如下实例目录:实现效果:具体思路:从和风天气api那里取得具体城市