Android Framework | Handler 消息机制
引言
消息机制是 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 = Message.obtain();
msg.what = 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 = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + 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 = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " 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 = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
public final boolean sendMessageAtFrontOfQueue(Message msg) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " 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方法是很多,但是最终都调用了enqueueMessage
方法。我们来看一下enqueueMessage
方法源码
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
msg.target 就是当前的 Handler,queue.enqueueMessage(msg, uptimeMillis);就是将消息插入消息队列;发送消息的过程结束了,我们来看一下接收消息过程
消息接收过程
当有消息时 Looper 调用 MessageQueue 的 next() 方法取出消息,然后调用 msg.target.dispatchMessage(msg) 方法, msg.target 就是 Handler,上面已说过,这个方法就是 Handler 消息的处理,我们看一下 Handler 的 dispatchMessage 源码
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Handler 构造方法
先看默认构造方法吧
public Handler() {
this(null, false);
}
会调用下面的构造方法
public Handler(Callback callback, boolean async) {
....省略
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
如果当前线程没有 Looper 就会抛出 Can't create handler inside thread that has not called Looper.prepare() 异常,这就是为什么在没有 Looper 的子线程中创建 Handler 会报这个异常原因了
Handler 还有一种特殊的构造函数,通过 Looper 来构造一个 Handler,构造函数源码如下
public Handler(Looper looper) {
this(looper, null, false);
}
为什么要有Android消息机制?
我们知道 Handler 的主要作用是将一个任务切换到某个指定的线程去执行,比如 Android 规定访问 UI 只能在主线程中进行,在大多数情况下如果在子线程中访问那么程序会抛异常
void checkThread(){
if(mThread != Thread.currentThread()){
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
为什么系统不允许在子线程中访问UI呢?
这是因为 Android 的 UI 控件不是线程安全的,如果在多线程中访问 UI 控件则会导致不可预期的状态
那为什么不对 UI 控件访问加锁呢?
缺点有两个:首先加锁会让UI控件的访问的逻辑变的复杂;其次,锁机制会降低UI的访问效率
那我们不用线程来操作不就行了吗?
但这是不可能的,因为 Android 的主线程不能执行耗时操作,否则会出现 ANR;所以,从各方面来说,Android 消息机制是为了解决在子线程中无法访问 UI 的矛盾
上边分析了那么多, 看了那么一大堆的代码,我们清楚的了解到了 Handler 机制对于 Android 系统的重要性;所以也有人说 Handler 消息机制是 Framework 层的发动机,这么考虑一下一点也不为过吧;有需要了解更多关于Android Framework 消息机制 相关资讯的朋友;可以简信发送 "进阶" ,即可获取一份 Android Framework 思维导图及学习手册,以便大家能够更好的学习 Android Framework
Android Framework 思维导图
资料部分内容展示如下:
《Handler 机制之 Thread》
- 线程概念
- Android 线程的实现
- 线程的阻塞
- 关于线程上下文切换
- 关于线程的安全问题
- 守护线程
- 线程的内存
《Handler 机制之 ThreadLocal》
- Java 中的 ThreadLocal
- ThreadLocal 的前世今生
- Android 中的 ThreadLocal
- Android 面试中的关于 ThreadLocal 的问题
- ThreadLocal 的结构
- ThreadLocal 静态类 ThreadLocal.Values
- ThreadLocal 的总结
完整版 Android Framework 思维导图及学习手册 获取方式: 简信发送 "进阶" 即可 直达获取
对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们
技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面
Android 架构师之路还很漫长,与君共勉