前言
在 Android 开发的多线程应用场景中, Handler 机制十分常用
今天, 我将手把手带你深入分析 Handler 机制的源码, 希望你们会喜欢
目录
示意图
1. Handler 机制简介
定义
一套 Android 消息传递机制
作用
在多线程的应用场景中, 将工作线程中需更新 UI 的操作信息 传递到 UI 主线程, 从而实现 工作线程对 UI 的更新处理, 最终实现异步消息的处理
示意图
为什么要用 Handler 消息传递机制
答: 多个线程并发更新 UI 的同时 保证线程安全具体描述如下
示意图
总结
使用 Handler 的原因: 将工作线程需操作 UI 的消息 传递 到主线程, 使得主线程可根据工作线程的需求 更新 UI, 从而避免线程操作不安全的问题
2. 储备知识
在阅读 Handler 机制的源码分析前, 请务必了解 Handler 的一些储备知识: 相关概念使用方式 & 工作原理
2.1 相关概念
关于 Handler 机制中的相关概念如下:
在下面的讲解中, 我将直接使用英文名讲解, 即 HandlerMessageMessage QueueLooper, 希望大家先熟悉相关概念
示意图
2.2 使用方式
Handler 使用方式 因发送消息到消息队列的方式不同而不同, 共分为 2 种: 使用
Handler.sendMessage()
使用 Handler.post()
下面的源码分析将依据使用步骤讲解
若还不了解, 请务必阅读文章: Android: 这是一份 Handler 消息传递机制 的使用教程
2.3 工作原理
理解 Handler 机制的工作原理, 能很大程序帮助理解其源码
具体请看文章: Android Handler: 图文解析 Handler 通信机制 的工作原理
3. Handler 机制的核心类
在源码分析前, 先来了解 Handler 机制中的核心类
3.1 类说明
Handler 机制 中有 3 个重要的类:
处理器 类(Handler)
消息队列 类(MessageQueue)
循环器 类(Looper)
3.2 类图
示意图
3.3 具体介绍
示意图
4. 源码分析
下面的源码分析将根据 Handler 的使用步骤进行
Handler 使用方式 因发送消息到消息队列的方式不同而不同, 共分为 2 种: 使用
Handler.sendMessage()
使用 Handler.post()
若还不了解, 请务必阅读文章: Android: 这是一份 Handler 消息传递机制 的使用教程
下面的源码分析将依据上述 2 种使用方式进行
方式 1: 使用 Handler.sendMessage()
使用步骤
- /**
- * 此处以 匿名内部类 的使用方式为例
- *$/ 步骤 1: 在主线程中 通过匿名内部类 创建 Handler 类对象
- private Handler mhandler = new Handler(){
- // 通过复写 handlerMessage()从而确定更新 UI 的操作
- @Override
- public void handleMessage(Message msg) {
- ...// 需执行的 UI 操作
- }
- };
- // 步骤 2: 创建消息对象
- Message msg = Message.obtain(); // 实例化消息对象
- msg.what = 1; // 消息标识
- msg.obj = "AA"; // 消息内容存放
- // 步骤 3: 在工作线程中 通过 Handler 发送消息到消息队列中
- // 多线程可采用 AsyncTask 继承 Thread 类实现 Runnable
- mHandler.sendMessage(msg);
- // 步骤 4: 开启工作线程(同时启动了 Handler)
- // 多线程可采用 AsyncTask 继承 Thread 类实现 Runnable
- 源码分析
- 下面, 我将根据上述每个步骤进行源码分析
- 步骤 1: 在主线程中 通过匿名内部类 创建 Handler 类对象
- /**
- * 具体使用
- */
- private Handler mhandler = new Handler(){
- // 通过复写 handlerMessage()从而确定更新 UI 的操作
- @Override
- public void handleMessage(Message msg) {
- ...// 需执行的 UI 操作
- }
- };
- /**
- * 源码分析: Handler 的构造方法
- * 作用: 初始化 Handler 对象 & 绑定线程
- * 注:
- * a. Handler 需绑定 线程才能使用; 绑定后, Handler 的消息处理会在绑定的线程中执行
- * b. 绑定方式 = 先指定 Looper 对象, 从而绑定了 Looper 对象所绑定的线程(因为 Looper 对象本已绑定了对应线程)
- * c. 即: 指定了 Handler 对象的 Looper 对象 = 绑定到了 Looper 对象所在的线程
- */
- public Handler() {
- this(null, false);
- // ->>分析 1
- }
- /**
- * 分析 1:this(null, false) = Handler(null,false)
- */
- public Handler(Callback callback, boolean async) {
- ...// 仅贴出关键代码
- // 1. 指定 Looper 对象
- mLooper = Looper.myLooper();
- if (mLooper == null) {
- throw new RuntimeException(
- "Can't create handler inside thread that has not called Looper.prepare()");
- }
- // Looper.myLooper()作用: 获取当前线程的 Looper 对象; 若线程无 Looper 对象则抛出异常
- // 即 : 若线程中无创建 Looper 对象, 则也无法创建 Handler 对象
- // 故 若需在子线程中创建 Handler 对象, 则需先创建 Looper 对象
- // 注: 可通过 Loop.getMainLooper()可以获得当前进程的主线程的 Looper 对象
- // 2. 绑定消息队列对象(MessageQueue)
- mQueue = mLooper.mQueue;
- // 获取该 Looper 对象中保存的消息队列对象(MessageQueue)
- // 至此, 保证了 handler 对象 关联上 Looper 对象中 MessageQueue
- }
从上面可看出:
当创建 Handler 对象时, 则通过 构造方法 自动关联当前线程的 Looper 对象 & 对应的消息队列对象(MessageQueue), 从而 自动绑定了 实现创建 Handler 对象操作的线程
那么, 当前线程的 Looper 对象 & 对应的消息队列对象(MessageQueue) 是什么时候创建的呢?
在上述使用步骤中, 并无 创建 Looper 对象 & 对应的消息队列对象 (MessageQueue) 这 1 步
步骤 1 前的隐式操作 1: 创建循环器对象(Looper) & 消息队列对象(MessageQueue)
步骤介绍
示意图
源码分析
- /**
- * 源码分析 1:Looper.prepare()
- * 作用: 为当前线程(子线程) 创建 1 个循环器对象(Looper), 同时也生成了 1 个消息队列对象(MessageQueue)
- * 注: 需在子线程中手动调用该方法
- */
- public static final void prepare() {
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- // 1. 判断 sThreadLocal 是否为 null, 否则抛出异常
- // 即 Looper.prepare()方法不能被调用两次 = 1 个线程中只能对应 1 个 Looper 实例
- // 注: sThreadLocal = 1 个 ThreadLocal 对象, 用于存储线程的变量
- sThreadLocal.set(new Looper(true));
- // 2. 若为初次 Looper.prepare(), 则创建 Looper 对象 & 存放在 ThreadLocal 变量中
- // 注: Looper 对象是存放在 Thread 线程里的
- // 源码分析 Looper 的构造方法 ->>分析 a
- }
- /**
- * 分析 a:Looper 的构造方法
- **/
- private Looper(boolean quitAllowed) {
- mQueue = new MessageQueue(quitAllowed);
- // 1. 创建 1 个消息队列对象(MessageQueue)
- // 即 当创建 1 个 Looper 实例时, 会自动创建一个与之配对的消息队列对象(MessageQueue)
- mRun = true;
- mThread = Thread.currentThread();
- }
- /**
- * 源码分析 2:Looper.prepareMainLooper()
- * 作用: 为 主线程(UI 线程) 创建 1 个循环器对象(Looper), 同时也生成了 1 个消息队列对象(MessageQueue)
- * 注: 该方法在主线程 (UI 线程) 创建时自动调用, 即 主线程的 Looper 对象自动生成, 不需手动生成
- *$/ 在 Android 应用进程启动时, 会默认创建 1 个主线程(ActivityThread, 也叫 UI 线程)
- // 创建时, 会自动调用 ActivityThread 的 1 个静态的 main()方法 = 应用程序的入口
- // main()内则会调用 Looper.prepareMainLooper()为主线程生成 1 个 Looper 对象
- /**
- * 源码分析: main()
- **/
- public static void main(String[] args) {
- ... // 仅贴出关键代码
- Looper.prepareMainLooper();
- // 1. 为主线程创建 1 个 Looper 对象, 同时生成 1 个消息队列对象(MessageQueue)
- // 方法逻辑类似 Looper.prepare()
- // 注: prepare(): 为子线程中创建 1 个 Looper 对象
- ActivityThread thread = new ActivityThread();
- // 2. 创建主线程
- Looper.loop();
- // 3. 自动开启 消息循环 ->>下面将详细分析
- }
总结:
创建主线程时, 会自动调用 ActivityThread 的 1 个静态的 main(); 而 main()内则会调用
Looper.prepareMainLooper()
为主线程生成 1 个 Looper 对象, 同时也会生成其对应的 MessageQueue 对象
即 主线程的 Looper 对象自动生成, 不需手动生成; 而子线程的 Looper 对象则需手动通过 Looper.prepare()创建
在子线程若不手动创建 Looper 对象 则无法生成 Handler 对象
根据 Handler 的作用(在主线程更新 UI), 故 Handler 实例的创建场景 主要在主线程
生成 Looper & MessageQueue 对象后, 则会自动进入消息循环: Looper.loop(), 即又是另外一个隐式操作
步骤 1 前的隐式操作 2: 消息循环
此处主要分析的是 Looper 类中的 loop()方法
- /**
- * 源码分析: Looper.loop()
- * 作用: 消息循环, 即从消息队列中获取消息分发消息到 Handler
- * 特别注意:
- * a. 主线程的消息循环不允许退出, 即无限循环
- * b. 子线程的消息循环允许退出: 调用消息队列 MessageQueue 的 quit()
- */
- public static void loop() {
- ...// 仅贴出关键代码
- // 1. 获取当前 Looper 的消息队列
- final Looper me = myLooper();
- if (me == null) {
- throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
- }
- // myLooper()作用: 返回 sThreadLocal 存储的 Looper 实例; 若 me 为 null 则抛出异常
- // 即 loop()执行前必须执行 prepare(), 从而创建 1 个 Looper 实例
- final MessageQueue queue = me.mQueue;
- // 获取 Looper 实例中的消息队列对象(MessageQueue)
- // 2. 消息循环(通过 for 循环)
- for (;;) {
- // 2.1 从消息队列中取出消息
- Message msg = queue.next();
- if (msg == null) {
- return;
- }
- // next(): 取出消息队列里的消息
- // 若取出的消息为空, 则线程阻塞
- // ->> 分析 1
- // 2.2 派发消息到对应的 Handler
- msg.target.dispatchMessage(msg);
- // 把消息 Message 派发给消息对象 msg 的 target 属性
- // target 属性实际是 1 个 handler 对象
- // ->>分析 2
- // 3. 释放消息占据的资源
- msg.recycle();
- }
- }
- /**
- * 分析 1:queue.next()
- * 定义: 属于消息队列类 (MessageQueue) 中的方法
- * 作用: 出队消息, 即从 消息队列中 移出该消息
- */
- Message next() {
- ...// 仅贴出关键代码
- // 该参数用于确定消息队列中是否还有消息
- // 从而决定消息队列应处于出队消息状态 or 等待状态
- int nextPollTimeoutMillis = 0;
- for (;;) {
- if (nextPollTimeoutMillis != 0) {
- Binder.flushPendingCommands();
- }
- // nativePollOnce 方法在 native 层, 若是 nextPollTimeoutMillis 为 - 1, 此时消息队列处于等待状态
- nativePollOnce(ptr, nextPollTimeoutMillis);
- synchronized (this) {
- final long now = SystemClock.uptimeMillis();
- Message prevMsg = null;
- Message msg = mMessages;
- // 出队消息, 即 从消息队列中取出消息: 按创建 Message 对象的时间顺序
- if (msg != null) {
- if (now <msg.when) {
- nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
- } else {
- // 取出了消息
- mBlocked = false;
- if (prevMsg != null) {
- prevMsg.next = msg.next;
- } else {
- mMessages = msg.next;
- }
- msg.next = null;
- if (DEBUG) Log.v(TAG, "Returning message:" + msg);
- msg.markInUse();
- return msg;
- }
- } else {
- // 若 消息队列中已无消息, 则将 nextPollTimeoutMillis 参数设为 - 1
- // 下次循环时, 消息队列则处于等待状态
- nextPollTimeoutMillis = -1;
- }
- ......
- }
- .....
- }
- }// 回到分析原处
- /**
- * 分析 2:dispatchMessage(msg)
- * 定义: 属于处理者类 (Handler) 中的方法
- * 作用: 派发消息到对应的 Handler 实例 & 根据传入的 msg 作出对应的操作
- */
- public void dispatchMessage(Message msg) {
- // 1. 若 msg.callback 属性不为空, 则代表使用了 post(Runnable r)发送消息
- // 则执行 handleCallback(msg), 即回调 Runnable 对象里复写的 run()
- // 上述结论会在讲解使用 post(Runnable r)方式时讲解
- if (msg.callback != null) {
- handleCallback(msg);
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- // 2. 若 msg.callback 属性为空, 则代表使用了 sendMessage(Message msg)发送消息(即此处需讨论的)
- // 则执行 handleMessage(msg), 即回调复写的 handleMessage(msg) ->> 分析 3
- handleMessage(msg);
- }
- }
- /**
- * 分析 3:handleMessage(msg)
- * 注: 该方法 = 空方法, 在创建 Handler 实例时复写 = 自定义消息处理方式
- **/
- public void handleMessage(Message msg) {
- ... // 创建 Handler 实例时复写
- }
总结:
消息循环的操作 = 消息出队 + 分发给对应的 Handler 实例
分发给对应的 Handler 的过程: 根据出队消息的归属者通过
dispatchMessage(msg)
进行分发, 最终回调复写的
handleMessage(Message msg)
, 从而实现 消息处理 的操作
特别注意: 在进行消息分发时
(dispatchMessage(msg))
, 会进行 1 次发送方式的判断:
若 msg.callback 属性不为空, 则代表使用了
post(Runnable r)
发送消息, 则直接回调 Runnable 对象里复写的 run()
若 msg.callback 属性为空, 则代表使用了
sendMessage(Message msg)
发送消息, 则回调复写的 handleMessage(msg)
至此, 关于步骤 1 的源码分析讲解完毕总结如下
示意图
步骤 2: 创建消息对象
- /**
- * 具体使用
- */
- Message msg = Message.obtain(); // 实例化消息对象
- msg.what = 1; // 消息标识
- msg.obj = "AA"; // 消息内容存放
- /**
- * 源码分析: Message.obtain()
- * 作用: 创建消息对象
- * 注: 创建 Message 对象可用关键字 new 或 Message.obtain()
- */
- public static Message obtain() {
- // Message 内部维护了 1 个 Message 池, 用于 Message 消息对象的复用
- // 使用 obtain()则是直接从池内获取
- synchronized (sPoolSync) {
- if (sPool != null) {
- Message m = sPool;
- sPool = m.next;
- m.next = null;
- m.flags = 0; // clear in-use flag
- sPoolSize--;
- return m;
- }
- // 建议: 使用 obtain()创建消息对象, 避免每次都使用 new 重新分配内存
- }
- // 若池内无消息对象可复用, 则还是用关键字 new 创建
- return new Message();
- }
总结
示意图
步骤 3: 在工作线程中 发送消息到消息队列中
多线程的实现方式: AsyncTask 继承 Thread 类实现 Runnable
- /**
- * 具体使用
- */
- mHandler.sendMessage(msg);
- /**
- * 源码分析: mHandler.sendMessage(msg)
- * 定义: 属于处理器类 (Handler) 的方法
- * 作用: 将消息 发送 到消息队列中(Message ->> MessageQueue)
- */
- public final boolean sendMessage(Message msg)
- {
- return sendMessageDelayed(msg, 0);
- // ->>分析 1
- }
- /**
- * 分析 1:sendMessageDelayed(msg, 0)
- **/
- public final boolean sendMessageDelayed(Message msg, long delayMillis)
- {
- if (delayMillis <0) {
- delayMillis = 0;
- }
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- // ->> 分析 2
- }
- /**
- * 分析 2:sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)
- **/
- public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
- // 1. 获取对应的消息队列对象(MessageQueue)
- MessageQueue queue = mQueue;
- // 2. 调用了 enqueueMessage 方法 ->>分析 3
- return enqueueMessage(queue, msg, uptimeMillis);
- }
- /**
- * 分析 3:enqueueMessage(queue, msg, uptimeMillis)
- **/
- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- // 1. 将 msg.target 赋值为 this
- // 即 : 把 当前的 Handler 实例对象作为 msg 的 target 属性
- msg.target = this;
- // 请回忆起上面说的 Looper 的 loop()中消息循环时, 会从消息队列中取出每个消息 msg, 然后执行 msg.target.dispatchMessage(msg)去处理消息
- // 实际上则是将该消息派发给对应的 Handler 实例
- // 2. 调用消息队列的 enqueueMessage()
- // 即: Handler 发送的消息, 最终是保存到消息队列 ->>分析 4
- return queue.enqueueMessage(msg, uptimeMillis);
- }
- /**
- * 分析 4:queue.enqueueMessage(msg, uptimeMillis)
- * 定义: 属于消息队列类 (MessageQueue) 的方法
- * 作用: 入队, 即 将消息 根据时间 放入到消息队列中(Message ->> MessageQueue)
- * 采用单链表实现: 提高插入消息删除消息的效率
- */
- boolean enqueueMessage(Message msg, long when) {
- ...// 仅贴出关键代码
- synchronized (this) {
- msg.markInUse();
- msg.when = when;
- Message p = mMessages;
- boolean needWake;
- // 判断消息队列里有无消息
- // a. 若无, 则将当前插入的消息 作为队头 & 若此时消息队列处于等待状态, 则唤醒
- if (p == null || when == 0 || when <p.when) {
- msg.next = p;
- mMessages = msg;
- needWake = mBlocked;
- } else {
- needWake = mBlocked && p.target == null && msg.isAsynchronous();
- Message prev;
- // b. 判断消息队列里有消息, 则根据 消息 (Message) 创建的时间 插入到队列中
- for (;;) {
- prev = p;
- p = p.next;
- if (p == null || when < p.when) {
- break;
- }
- if (needWake && p.isAsynchronous()) {
- needWake = false;
- }
- }
- msg.next = p;
- prev.next = msg;
- }
- if (needWake) {
- nativeWake(mPtr);
- }
- }
- return true;
- }
- // 之后, 随着 Looper 对象的无限消息循环
- // 不断从消息队列中取出 Handler 发送的消息 & 分发到对应 Handler
- // 最终回调 Handler.handleMessage()处理消息
总结
Handler 发送消息的本质 = 为该消息定义 target 属性(即本身实例对象) & 将消息入队到绑定线程的消息队列中具体如下:
示意图
至此, 关于使用
Handler.sendMessage()
的源码解析完毕
总结
根据操作步骤的源码分析总结
示意图
工作流程总结
下面, 将顺着文章: 工作流程再理一次
示意图
示意图
方式 2: 使用 Handler.post()
使用步骤
- // 步骤 1: 在主线程中创建 Handler 实例
- private Handler mhandler = new mHandler();
- // 步骤 2: 在工作线程中 发送消息到消息队列中 & 指定操作 UI 内容
- // 需传入 1 个 Runnable 对象
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- ... // 需执行的 UI 操作
- }
- });
- // 步骤 3: 开启工作线程(同时启动了 Handler)
- // 多线程可采用 AsyncTask 继承 Thread 类实现 Runnable
源码分析
下面, 我将根据上述每个步骤进行源码分析
实际上, 该方式与方式 1 中的
Handler.sendMessage()
工作原理相同源码分析类似, 下面将主要讲解不同之处
步骤 1: 在主线程中创建 Handler 实例
- /**
- * 具体使用
- */
- private Handler mhandler = new Handler();
- // 与方式 1 的使用不同: 此处无复写 Handler.handleMessage()
- /**
- * 源码分析: Handler 的构造方法
- * 作用:
- * a. 在此之前, 主线程创建时隐式创建 Looper 对象 MessageQueue 对象
- * b. 初始化 Handler 对象绑定线程 & 进入消息循环
- * 此处的源码分析类似方式 1, 此处不作过多描述
- */
步骤 2: 在工作线程中 发送消息到消息队列中
- /**
- * 具体使用
- * 需传入 1 个 Runnable 对象复写 run()从而指定 UI 操作
- */
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- ... // 需执行的 UI 操作
- }
- });
- /**
- * 源码分析: Handler.post(Runnable r)
- * 定义: 属于处理者类 (Handler) 中的方法
- * 作用: 定义 UI 操作将 Runnable 对象封装成消息对象 & 发送 到消息队列中(Message ->> MessageQueue)
- * 注:
- * a. 相比 sendMessage(),post()最大的不同在于, 更新的 UI 操作可直接在重写的 run()中定义
- * b. 实际上, Runnable 并无创建新线程, 而是发送 消息 到消息队列中
- */
- public final boolean post(Runnable r)
- {
- return sendMessageDelayed(getPostMessage(r), 0);
- // getPostMessage(r) 的源码分析 ->>分析 1
- // sendMessageDelayed()的源码分析 ->>分析 2
- }
- /**
- * 分析 1:getPostMessage(r)
- * 作用: 将传入的 Runable 对象封装成 1 个消息对象
- **/
- private static Message getPostMessage(Runnable r) {
- // 1. 创建 1 个消息对象(Message)
- Message m = Message.obtain();
- // 注: 创建 Message 对象可用关键字 new 或 Message.obtain()
- // 建议: 使用 Message.obtain()创建,
- // 原因: 因为 Message 内部维护了 1 个 Message 池, 用于 Message 的复用, 使用 obtain()直接从池内获取, 从而避免使用 new 重新分配内存
- // 2. 将 Runable 对象 赋值给消息对象 (message) 的 callback 属性
- m.callback = r;
- // 3. 返回该消息对象
- return m;
- } // 回到调用原处
- /**
- * 分析 2:sendMessageDelayed(msg, 0)
- * 作用: 实际上, 从此处开始, 则类似方式 1 = 将消息入队到消息队列,
- * 即 最终是调用 MessageQueue.enqueueMessage()
- **/
- public final boolean sendMessageDelayed(Message msg, long delayMillis)
- {
- if (delayMillis <0) {
- delayMillis = 0;
- }
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- // 请看分析 3
- }
- /**
- * 分析 3:sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)
- **/
- public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
- // 1. 获取对应的消息队列对象(MessageQueue)
- MessageQueue queue = mQueue;
- // 2. 调用了 enqueueMessage 方法 ->>分析 3
- return enqueueMessage(queue, msg, uptimeMillis);
- }
- /**
- * 分析 4:enqueueMessage(queue, msg, uptimeMillis)
- **/
- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- // 1. 将 msg.target 赋值为 this
- // 即 : 把 当前的 Handler 实例对象作为 msg 的 target 属性
- msg.target = this;
- // 请回忆起上面说的 Looper 的 loop()中消息循环时, 会从消息队列中取出每个消息 msg, 然后执行 msg.target.dispatchMessage(msg)去处理消息
- // 实际上则是将该消息派发给对应的 Handler 实例
- // 2. 调用消息队列的 enqueueMessage()
- // 即: Handler 发送的消息, 最终是保存到消息队列
- return queue.enqueueMessage(msg, uptimeMillis);
- }
- // 注: 实际上从分析 2 开始, 源码 与 sendMessage(Message msg)发送方式相同
从上面的分析可看出:
消息对象的创建 = 内部 根据 Runnable 对象而封装
发送到消息队列的逻辑 = 方式 1 中
sendMessage(Message msg)
下面, 我们重新回到步骤 1 前的隐式操作 2: 消息循环, 即 Looper 类中的 loop()方法
- /**
- * 源码分析: Looper.loop()
- * 作用: 消息循环, 即从消息队列中获取消息分发消息到 Handler
- * 特别注意:
- * a. 主线程的消息循环不允许退出, 即无限循环
- * b. 子线程的消息循环允许退出: 调用消息队列 MessageQueue 的 quit()
- */
- public static void loop() {
- ...// 仅贴出关键代码
- // 1. 获取当前 Looper 的消息队列
- final Looper me = myLooper();
- if (me == null) {
- throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
- }
- // myLooper()作用: 返回 sThreadLocal 存储的 Looper 实例; 若 me 为 null 则抛出异常
- // 即 loop()执行前必须执行 prepare(), 从而创建 1 个 Looper 实例
- final MessageQueue queue = me.mQueue;
- // 获取 Looper 实例中的消息队列对象(MessageQueue)
- // 2. 消息循环(通过 for 循环)
- for (;;) {
- // 2.1 从消息队列中取出消息
- Message msg = queue.next();
- if (msg == null) {
- return;
- }
- // next(): 取出消息队列里的消息
- // 若取出的消息为空, 则线程阻塞
- // 2.2 派发消息到对应的 Handler
- msg.target.dispatchMessage(msg);
- // 把消息 Message 派发给消息对象 msg 的 target 属性
- // target 属性实际是 1 个 handler 对象
- // ->>分析 1
- // 3. 释放消息占据的资源
- msg.recycle();
- }
- }
- /**
- * 分析 1:dispatchMessage(msg)
- * 定义: 属于处理者类 (Handler) 中的方法
- * 作用: 派发消息到对应的 Handler 实例 & 根据传入的 msg 作出对应的操作
- */
- public void dispatchMessage(Message msg) {
- // 1. 若 msg.callback 属性不为空, 则代表使用了 post(Runnable r)发送消息(即此处需讨论的)
- // 则执行 handleCallback(msg), 即回调 Runnable 对象里复写的 run()->> 分析 2
- if (msg.callback != null) {
- handleCallback(msg);
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- // 2. 若 msg.callback 属性为空, 则代表使用了 sendMessage(Message msg)发送消息(即此处需讨论的)
- // 则执行 handleMessage(msg), 即回调复写的 handleMessage(msg)
- handleMessage(msg);
- }
- }
- /**
- * 分析 2:handleCallback(msg)
- **/
- private static void handleCallback(Message message) {
- message.callback.run();
- // Message 对象的 callback 属性 = 传入的 Runnable 对象
- // 即回调 Runnable 对象里复写的 run()
- }
至此, 你应该明白使用 Handler.post()的工作流程: 与方式 1
(Handler.sendMessage())
类似, 区别在于:
不需外部创建消息对象, 而是内部根据传入的 Runnable 对象 封装消息对象
回调的消息处理方法是: 复写 Runnable 对象的 run()
二者的具体异同如下:
示意图
至此, 关于使用 Handler.post()的源码解析完毕
总结
根据操作步骤的源码分析总结
示意图
工作流程总结
下面, 将顺着文章: 工作流程再理一次
示意图
示意图
至此, 关于 Handler 机制的源码全部分析完毕
5. 总结
本文详细分析了 Handler 机制的源码, 文字总结 & 流程图如下:
示意图
示意图
示意图
示意图
下面我将继续深入讲解 Android 中的 Handler 异步通信传递机制的相关知识, 如 工作机制流程源码解析等, 有兴趣可以继续关注 Carson_Ho 的安卓开发笔记
请点赞! 因为你的鼓励是我写作的最大动力!
来源: http://www.jianshu.com/p/b4d745c7ff7a