前言
Handler可以说是老生常谈了,因为它在整个Android的系统中是非常重要的一部分,学习它的原理是很有必要的。本文带来的分享是对Handler原理的全面解析,相信对日常的开发和面试会有很大的帮助,下面我们一起看看它的原理。
正文
在讲解Handler原理之前,我们先通过一张图片看看它的整个流程:
当然,我们接下来所讲的Handler原理,不仅仅是Handler本身,还包括MessageQueue、Looper等类。
Handler的作用
在日常开发中,我们很多时候需要切换线程去做某件事情,比如在工作线程做好计算后,需要切换到主线程去更新ui,那么这个时候便可以使用Handler来进行线程的切换,又比如我们想做一个延迟任务,也可以使用Handler去开启一个延迟任务等等。
Handler
创建:
Handler的构造函数最后会调用到下面的构造函数:
public Handler(@Nullable Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
构造函数初始化Looper成员,会对Looper进行检查,如果之前还没初始化,则会抛异常,所以创建Handler之前,需要确保当前线程的Looper已经创建了,Looper创建后会与当前线程绑定存放起来,至于它得怎么创建,我们后面会讲到。
但是我们在主线程中,则无需去创建Looper,因为在ActivityThread的main方法里边,系统已经帮我们创建好了:
//只保留核心代码
public static void main(String[] args) {
Looper.prepareMainLooper();
Looper.loop();
}
Looper.prepareMainLooper()里边会去创建一个Looper,并且这个Looper是在主线程中。
发送消息:
发送消息之前,需要创建Message,Message可以说是整个流程的载体,它承载着一些信息。它的创建方式如下:
new Message()
Message.obtain()
handler.obtainMessage()
//直接new跟obtain有什么区别呢?obtain的话,会优先到池子里拿,池子没有到话再创建一个,所以我们一般优先考虑obtain的方式去获取Message。
//发送消息
handler.sendMessage(msg);
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
// 省略校验
return enqueueMessage(queue, msg, uptimeMillis);
}
发送消息的最后都会调用到sendMessageAtTime方法,它里边调用到是enqueueMessage方法:
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
主要做了三件事:
- 将msg的target设置为this,在消息分发时会用到,后面内容分析。
- 如果当前Handler支持异步,那么会将msg设置为异步消息,用于异步屏障使用,后面分析
- 调用MessageQueue的enqueueMessage方法。
下面我们一起看看MessageQueue
处理消息:
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
从上面的代码我们可以看到分发的顺序是:
- 如果Message有设置callback,则使用messaeg的callback进行回调,其实我们平时使用handler.post()/postDelay(),都会使用将Runnable赋值给Message的callback。
- 如果Handler有设置callback,则会先回调Handler的callback。
- 最后是Handler的handleMessage,这也是我们常见的一个方法,初始化Handler的时候去复写这个方法,并在里边进行消息的处理。
MessageQueue
内部时一个链表结构,用于存放Message和提供Message
插入消息:
上面讲到的enqueueMessage方法,就是用来存放Message的:
//已精简了部分代码
boolean enqueueMessage(Message msg