作者:以下犯上LOVE_845 | 来源:互联网 | 2023-09-17 21:06
引言 消息机制 是 Android 中重要的线程间通信手段 ;它的存在可以让一个线程通知另一个线程去工作
众所周知 Handler 在 Android 中的地位非常重要 , 从处理异步线程任务队列的 HandlerThread 到从子线程与UI线程的通信 , 再到 ActivityThread 中四大组件 的 sendMessage 调度, 再到进程间通信与之关联 Messenger 可以说是从头到尾贯穿 的整个 Android 系统 的枝枝蔓蔓 ;所以说搞明白,搞懂 Handler 消息运行机制与原理至关重要
下面我们来看一下 Handler 的工作流程图
我们先从 Handler 源码看起吧,下一步看 MessageQueue 源码,最后看 Looper 源码
Handler 工作原理 Handler的主要工作是发送消息和接受消息
消息发送过程 消息的发送我们可以通过一系列 send 和 post 方法 来看一下这些 send 和 post 方法源码吧
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;与君共勉