0. 场景重现
面试官:请做下自我介绍
我:我叫孙小胖儿,吧啦吧啦吧啦。。。。
面试官:好的,那我们来问点技术问题,请问你对Handler机制了解么
我:Handler机制主要是由Handler、Message、MessageQueue、Looper组成的,它们,它们,嗯。。。。呃。。。。
面试官:好了,咱们的面试就到这儿吧
我:哦,好的。
1. Handler 是什么
1.1 Handler 的定义
以下是 Android 对于Handler
的定义^[1]^
A Handler allows you to send and process
Message
and Runnable objects associated with a thread'sMessageQueue
. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler it is bound to aLooper
. It will deliver messages and runnables to that Looper's message queue and execute them on that Looper's thread.There are two main uses for a Handler: (1) to schedule messages and runnables to be executed at some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
简单说就是:我们可以通过Handler
发送并处理与线程的消息队列相关联的Message
和Runnable
(其实Runnable 最终会被封装进 Message,所以 Runnable 本质上也是个 Message,这个后面再展开说)。每个 Handler 实例都会跟一个线程及其消息队列关联,当创建 Handler 的时候,它会和一个 Looper 绑定。 Handler有两个主要的用途:
(1) 在未来的某个时间执行 Message 或者 Runnable
(2) 在不同的线程间执行一些操作
1.2 Handler 的基本用法
java
import android.os.Handler;
import android.os.Message;
public class HandlerTestActivity extends AppCompatActivity {
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case 1:
// do something
break;
}
}
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_test);
// message形式
sendMessage();
// Runnable形式
postRunnable();
}
private void sendMessage() {
Message msg = Message.obtain();
msg.what = 1;
mHandler.sendMessage(msg);
}
private void postRunnable() {
mHandler.post(new Runnable() {
@Override
public void run() {
// do something
}
});
}
}
上面这段代码就是Handler最基本的用法了,首先实例化一个Handler对象(第6行),然后通过sendMessage(sendMessage()方法) 或者 post(postRunnable()方法)的形式,来做一些线程相关的操作了。
咦?这里只有Handler
和 Message
,并没有 MessageQueue 和 Looper 啊,搞咩啊~~~
2. Handler 机制探究
2.1 Handler 把 Message 送到哪里去了
通过 Handler 的基本用法,我们已经知道 Handler 通过 sendMessage 方法把 Message 发送了出去,但是 Message 被送到哪里去了呢?我们来看看 sendMessage 方法都做了什么。 从上述代码中可以看出,虽然我们调用的是Handler#sendMessage
这个方法,但是实际执行的代码是在 sendMessageAtTime
这个方法中,在这个方法中出现了一个和 Message 相关的东西:MessageQueue
,我们继续往下看 在enqueueMessage这个方法中,我们看到,最后执行的是
java
queue.enqueueMessage(msg, uptimeMillis);
而这个 queue 正是在 sendMessageAtTime
中定义,然后传入到enqueueMessage 这个方法中的。至此,Handler 终于是将 Message 放到了 MessageQueue
2.2 Message 是怎么回到 Handler 的
我们实例化一个Handler对象(假定命名为:mHandler)的时候,会重写 handleMessage 这个方法,这样当我们在调用 Handler#sendMessage
这个方法的时候,才会由这个 mHandler 来处理 Message,那么,问题来了,这个 Message 又是怎么回到 Handler 的呢?
我们仔细看一下在【2.1节】提到的 enqueueMessage 这个方法 可以看到这个方法体内的第一行代码是:
java
msg.target = this;
也就是说,Handler 把它自己存到了 Message 的 target 中,这样做的意义是什么呢? 说这个之前,我们先来看看 Handler 的构造方法
从图中可以看到,
java
public Handler() {
this(null, false);
}
![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/526179d2b0ec4f2e8a232eb7be2c9579~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=2218&h=2342&s=575489&e=png&b=202124)
public Handler(@Nullable Callback callback) {
this(callback, false);
}
最终调用的是下面这个构造方法,而在这个构造方法中,Looper
终于是浮出了水面。
java
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;
}
注意 :下面这两个方法,从API 30
开始废弃了,官方文档给出的解释是:在Handler
的构造方法中隐式的选择Looper
会引发 Bug^[2]^
java
public Handler() {
this(null, false);
}
![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6b5dd0eed1284ff4ab5dcc6c0b9ec269~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=2218&h=2342&s=575489&e=png&b=202124)
public Handler(@Nullable Callback callback) {
this(callback, false);
}
好了,言归正传,我们来看看这个Looper
是什么。
Looper
中有两个比较重要的方法,一个是prepare()
方法,一个是loop()
方法,我们先说prepare()
方法。 从上图可以看到,在prepare()
方法中,实例化了一个Looper
对象,而在Looper
的构造方法中,实例化了消息队列(见下图)
至此,Looper、MessageQueue、Message、Handler 这四者都出现了,也通过 MessageQueue、Message 关联到一起了。
那么我们接下来看看 Looper 中另一个比较重要的方法:loop()
loop()方法中有个for循环,还是个死循环,在这里有个方法,名为:loopOnce,我们看看它做了哪些事情 在 loopOnce 这个方法中,我们可以看到,它首先调用了MessageQueue的next()方法,获取到了Message(图中第161行代码) 在对这个取出来的 Message 做了一些列处理后,执行了 msg.target.dispatchMessage 这个代码。还记得我们前面说过的msg.target是什么么?对了,它就是发送这个 message 的 Handler,好了,Handler 向消息队列发送的消息,最终还是又回到了这个 Handler 里,让它自己处理。最后来看看这个 dispatchMessage()
方法做了什么 好了,现在 Handler、Message、MessageQueue、Looper这四个终于是形成了一个回环。它们之间的工作流程如下:
3. 扩展一下
3.1 为什么说 Runnable 也是 Message
我们来看下 Handler#post()
方法做了什么,就知道了 可以看到,在post方法里调用的还是 sendMessageDelayed() 方法,但是有个区别,传给sendMessageDelayed() 的第一个参数,是从 getPostMessage() 这个方法取得,我们跟进去看一下 在这里可以看到,Runnable被当做了Message的callback保存了下来,因此可以简单的认为 Runnable 也是 Message
3.2 Handler是怎么实现线程切换的
Handler 实现线程切换,其实依赖的是 Looper,因为在 Handler 初始化的时候就跟 Looper 绑定了,而Looper 又是跟线程绑定的,所以,Handler 最后执行 HandleMessage() 方法的时候所在的线程就是 Looper 所在的线程。
java
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;
...
}
Looper.loop()
-> MessageQueue.next()
-> Message.target.dispatchMessage()
-> Handler.handleMessage()
通常情况下,我们在使用 Handler 的时候除非特别指定,否则用的都是主线程的 Looper,因此子线程发送消息以后,经过Looper#loop()
->MessageQueue.next()
->Message.target.dispatchMessage()
这一系列的调用之后,会回到主线程执行Handler#handleMessage()
3.3 为什么能在主线程直接使用 Looper
那是就得从Looper#prepareMainLooper()
方法说起了 初看这个方法,好像没有什么特别之处,不过仔细看下箭头指向的那行代码 prepare(false),这里传入的是false,从参数的提示可以看到是不允许退出,因此主线程的Looper是不能退出的。
再看下这个方法的注释,即@deprecated那里写的,你的应用程序的main looper已经被Android 环境创建了,那我们来验证一下 全局搜索一下prepareMainLooper(),可以看到在ActivityThread#main()
方法中调用了 Looper.prepareMainLooper(),所以这也就印证了注释中的说明,确实是 Android 帮我们创建了,因此我们可以直接在主线程(UI线程)使用Looper了。
3.4 Message 的创建
在Android 源码里,对于 Message ,有个特别说明 建议我们使用Message#obtain()
或Handler#obtainMessage()
这个两个方法来创建 Message 对象,从这段描述来看,Android 给 Message 设计了一个回收机制,所以为了节省内存开销,还是按照官方推荐的方式来获取 Message 吧
4. 总结
- Handler 背后还有 Looper、MessageQueue、Message
- message:消息。
- MessageQueue:消息队列,负责消息的存储与管理,负责管理由 Handler 发送过来的 Message。读取会自动删除消息,单链表维护,插入和删除上有优势。在其next()方法中会无限循环,不断判断是否有消息,有就返回这条消息并移除。
- Looper:消息循环器,负责关联线程以及消息的分发,在该线程下从 MessageQueue获取 Message,分发给Handler,Looper创建的时候会创建一个 MessageQueue,调用loop()方法的时候消息循环开始,其中会不断调用messageQueue的next()方法,当有消息就处理,否则阻塞在messageQueue的next()方法中。当Looper的quit()被调用的时候会调用messageQueue的quit(),此时next()会返回null,然后loop()方法也就跟着退出。
- Handler:消息处理器,负责发送并处理消息,面向开发者,提供 API,并隐藏背后实现的细节。
- 使用 Handler 前,要先创建 Looper 或者使用主线程的 Looper
- 主线程的 Looper 不允许退出
- Runnable 被封装进了 Message,可以说是一个特殊的 Message
5. 参考资料
6. 备注
[1]:Handler
重新出发再学习,写下来一是加深印象,二是记录下这个重新学习的过程,有不足之处欢迎指正