热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AndroidFramework|Handler消息机制详解

引言消息机制是Android中重要的线程间通信手段;它的存在可以让一个线程通知另一个线程去工作众所周知Handler在Android中的地位非常重要,从

引言


消息机制Android 中重要的线程间通信手段;它的存在可以让一个线程通知另一个线程去工作


众所周知 Handler 在 Android 中的地位非常重要, 从处理异步线程任务队列的 HandlerThread 到从子线程与UI线程的通信, 再到 ActivityThread四大组件sendMessage 调度, 再到进程间通信与之关联 Messenger 可以说是从头到尾贯穿的整个 Android 系统枝枝蔓蔓;所以说搞明白,搞懂 Handler 消息运行机制与原理至关重要

下面我们来看一下 Handler 的工作流程图

我们先从 Handler 源码看起吧,下一步看 MessageQueue 源码,最后看 Looper 源码


Handler 工作原理

Handler的主要工作是发送消息和接受消息


消息发送过程

消息的发送我们可以通过一系列 sendpost 方法
来看一下这些 sendpost 方法源码吧

public final boolean sendEmptyMessage(int what){return sendEmptyMessageDelayed(what, 0);}public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {Message msg &#61; Message.obtain();msg.what &#61; what;return sendMessageDelayed(msg, delayMillis);}public final boolean sendMessage(Message msg){return sendMessageDelayed(msg, 0);}public final boolean sendMessageDelayed(Message msg, long delayMillis){if (delayMillis < 0) {delayMillis &#61; 0;}return sendMessageAtTime(msg, SystemClock.uptimeMillis() &#43; delayMillis);}public final boolean post(Runnable r){return sendMessageDelayed(getPostMessage(r), 0);}public final boolean postDelayed(Runnable r, long delayMillis){return sendMessageDelayed(getPostMessage(r), delayMillis);}public final boolean postAtTime(Runnable r, Object token, long uptimeMillis){return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);}public boolean sendMessageAtTime(Message msg, long uptimeMillis) {MessageQueue queue &#61; mQueue;if (queue &#61;&#61; null) {RuntimeException e &#61; new RuntimeException(this &#43; " sendMessageAtTime() called with no mQueue");Log.w("Looper", e.getMessage(), e);return false;}return enqueueMessage(queue, msg, uptimeMillis);}public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {Message msg &#61; Message.obtain();msg.what &#61; what;return sendMessageAtTime(msg, uptimeMillis);}public final boolean sendMessageAtFrontOfQueue(Message msg) {MessageQueue queue &#61; mQueue;if (queue &#61;&#61; null) {RuntimeException e &#61; new RuntimeException(this &#43; " sendMessageAtTime() called with no mQueue");Log.w("Looper", e.getMessage(), e);return false;}return enqueueMessage(queue, msg, 0);}public final boolean postAtFrontOfQueue(Runnable r){return sendMessageAtFrontOfQueue(getPostMessage(r));}

Handler 的send和post方法是很多&#xff0c;但是最终都调用了enqueueMessage方法。我们来看一下enqueueMessage方法源码

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target &#61; this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);}

msg.target 就是当前的 Handler&#xff0c;queue.enqueueMessage(msg, uptimeMillis);就是将消息插入消息队列&#xff1b;发送消息的过程结束了&#xff0c;我们来看一下接收消息过程


消息接收过程

当有消息时 Looper 调用 MessageQueue 的 next() 方法取出消息&#xff0c;然后调用 msg.target.dispatchMessage(msg) 方法&#xff0c; msg.target 就是 Handler&#xff0c;上面已说过&#xff0c;这个方法就是 Handler 消息的处理&#xff0c;我们看一下 Handler 的 dispatchMessage 源码

public void dispatchMessage(Message msg) {if (msg.callback !&#61; null) {handleCallback(msg);} else {if (mCallback !&#61; null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}

Handler 构造方法

先看默认构造方法吧

public Handler() {this(null, false);
}

会调用下面的构造方法

public Handler(Callback callback, boolean async) {....省略mLooper &#61; Looper.myLooper();if (mLooper &#61;&#61; null) {throw new RuntimeException("Can&#39;t create handler inside thread that has not called Looper.prepare()");}mQueue &#61; mLooper.mQueue;mCallback &#61; callback;mAsynchronous &#61; async;
}

如果当前线程没有 Looper 就会抛出 Can’t create handler inside thread that has not called Looper.prepare() 异常&#xff0c;这就是为什么在没有 Looper 的子线程中创建 Handler 会报这个异常原因了

Handler 还有一种特殊的构造函数&#xff0c;通过 Looper 来构造一个 Handler&#xff0c;构造函数源码如下

public Handler(Looper looper) {this(looper, null, false);
}

为什么要有Android消息机制&#xff1f;

我们知道 Handler 的主要作用是将一个任务切换到某个指定的线程去执行&#xff0c;比如 Android 规定访问 UI 只能在主线程中进行&#xff0c;在大多数情况下如果在子线程中访问那么程序会抛异常

void checkThread(){if(mThread !&#61; Thread.currentThread()){ throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); }
}

为什么系统不允许在子线程中访问UI呢&#xff1f;

这是因为 Android 的 UI 控件不是线程安全的&#xff0c;如果在多线程中访问 UI 控件则会导致不可预期的状态


那为什么不对 UI 控件访问加锁呢&#xff1f;

**缺点有两个&#xff1a;**首先加锁会让UI控件的访问的逻辑变的复杂&#xff1b;其次&#xff0c;锁机制会降低UI的访问效率


那我们不用线程来操作不就行了吗&#xff1f;

但这是不可能的&#xff0c;因为 Android 的主线程不能执行耗时操作&#xff0c;否则会出现 ANR&#xff1b;所以&#xff0c;从各方面来说&#xff0c;Android 消息机制是为了解决在子线程中无法访问 UI 的矛盾

上边分析了那么多&#xff0c; 看了那么一大堆的代码&#xff0c;我们清楚的了解到了 Handler 机制对于 Android 系统的重要性&#xff1b;所以也有人说 Handler 消息机制是 Framework 层的发动机&#xff0c;这么考虑一下一点也不为过吧&#xff1b;有需要了解更多关于Android Framework 消息机制 相关资讯的朋友&#xff1b;可以私信发送 “进阶” &#xff0c;即可获取一份 Android Framework 思维导图及学习手册&#xff0c;以便大家能够更好的学习 Android Framework


Android Framework 思维导图

资料部分内容展示如下&#xff1a;


《Handler 机制之 Thread》


  • 线程概念
  • Android 线程的实现
  • 线程的阻塞
  • 关于线程上下文切换
  • 关于线程的安全问题
  • 守护线程
  • 线程的内存


《Handler 机制之 ThreadLocal》


  • Java 中的 ThreadLocal
  • ThreadLocal 的前世今生
  • Android 中的 ThreadLocal
  • Android 面试中的关于 ThreadLocal 的问题
  • ThreadLocal 的结构
  • ThreadLocal 静态类 ThreadLocal.Values
  • ThreadLocal 的总结

完整版 Android Framework 思维导图及学习手册 获取方式&#xff1a; 私信发送 “进阶” 即可 直达获取

对于程序员来说&#xff0c;要学习的知识内容、技术有太多太多&#xff0c;要想不被环境淘汰就只有不断提升自己&#xff0c;从来都是我们去适应环境&#xff0c;而不是环境来适应我们

技术是无止境的&#xff0c;你需要对自己提交的每一行代码、使用的每一个工具负责&#xff0c;不断挖掘其底层原理&#xff0c;才能使自己的技术升华到更高的层面

Android 架构师之路还很漫长&#xff0c;与君共勉


推荐阅读
author-avatar
以下犯上LOVE_845
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有