Android中的消息机制--Handler

前言

网上关于Handler机制运行原理的文章已经很多,但毕竟不是自己的,也不一定适合自己的阅读习惯!


一、概述

Android 的消息机制主要是指 Handler 的运行机制, Handler 的运行需要底层的 MessageQueue 和 Looper 支撑,这三者实际上是一个整体 ( 配套使用 ) ,只不过我们在开发过程中比较多的接触到 Handler 而已。

说到 Handler ,很多人都知道是为了更新 UI ,这不错,但这只是 Handler 的一个应用场景而已。

Handler 出现的原因,我想是因为不能在主线程中做耗时操作,一旦耗时操作超过 5s 就会出现 ANR 异常,下面代码是 Handler 的最常用用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MainActivity extends AppCompatActivity {
private Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//主线程中处理发送过来的message
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//子线程中发送Handler消息
new Thread(){
@Override
public void run() {
Message msg = new Message();
msg.what = 1;
myHandler.sendMessage(msg);
}
}.start();
}
}
}

注意:

线程中默认是没有 Looper的,如果想要使用 Handler 就必须为线程创建 Looper ,否则会报错,Looper 是运行在 Handler 所在的线程中的。

主线程比较特殊,它在创建的时候就会初始化 Looper,会调用 Looper.prepaerMainLooper() 来创建主线程的 looper 以及 MessageQueue ,也就是说,在主线程中默认可以使用 Handler 。

大致的原理:

Handler 通过 send 或 post 的 一系列方法发送 message 到 MessageQueue 。

MessageQueue 翻译过来叫做消息队列,内部存储 Handler 发送过来的一系列消息,仅仅能存储消息,数据存储结构为单链表。

Looper 会以无限循环的方式从 MessageQueue 中查找是否有新消息,如果有就处理消息,否则就一直等待着。

二、详细分析

主要介绍下 ThreadLocal 、 Handler 、 MessageQueue 、Looper

1. ThreadLocal

ThreadLocal 是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只能在指定线程中才可以获取到存储的数据。

介绍 ThreadLocal 是因为不同线程的 Handler 获取对应 Looper 采用的就是这个原理。

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MainActivity extends AppCompatActivity {
//ThreadLocal 对象,存储的是 boolean 值
private ThreadLocal<Boolean> mBooleanThreadLocal = new ThreadLocal<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBooleanThreadLocal.set(true);
Log.i("Thread---Main:",mBooleanThreadLocal.get()+"");
new Thread("Thread---1"){
@Override
public void run() {
mBooleanThreadLocal.set(false);
Log.i("Thread---1:",mBooleanThreadLocal.get()+"");
}
}.start();
new Thread("Thread---2"){
@Override
public void run() {
Log.i("Thread---2:",mBooleanThreadLocal.get()+"");
}
}.start();
}

代码中,在主线程中设置 mBooleanThreadLocal 为 true ,在 Thread—1 中设置 mBooleanThreadLocal 为 false ,在 Thread—2 中没有设置, mBooleanThreadLocal 通过 set() 和 get() 方法进行数据的设置和取出操作。

打印出来的结果为:

1
2
3
12945-12945/? I/Thread---Main:: true
12945-12959/? I/Thread---1:: false
12945-12960/? I/Thread---2:: null

从上边的日志可以看出,在不同线程中访问同一个 ThreadLocal 对象,
获得的值却是不一样的,原因就是:ThreadLocal 内部会从各自的线程中取出一个数组,
然后再从数组中根据当前 ThreadLocal 的索引去查找对应的 value 值,而不同线程中的数组是不同的,
所以取出的值也不一样。

2. MessageQueue

翻译过来为消息队列,其主要包含两个操作:插入和读取,分别对应 MessageQueue 的两个方法 enqueueMessage() 和 next() ,另外,读取过的消息会删除掉!

3. Looper

Looper 会不停的从 MessageQueue 中查看是否有新消息,有就立刻处理,否则就一直阻塞,在 Looper 的构造方法中会创建一个 MessageQueue 对象,再次印证了那四个字—配套使用。

1
2
3
4
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

除了主线程之外,在其他线程中如何创建 Looper 对象,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
new Thread("Thread---1"){
@Override
public void run() {
//创建 Looper 对象
Looper.prepare();
Message msg = new Message();
msg.what = 1;
myHandler.sendMessage(msg);
//开启消息循环
Looper.loop();
}
}.start();

获取主线程 Looper, 通过方法:Looper.getMainLooper();

Looper 退出,有两个方法,Looper 的 quit() 和 quitSafely() ,其内部还是让 MessageQueue 的 next 方法返回 null , next 方法返回 null 是唯一的退出方式 ,建议不需要的时候终止 Looper。

quit() 是直接退出 Looper 。

quitSafely() 是把已有的消息处理完之后才安全退出。

4. Handler

handler 的工作主要是发送和接收消息的过程

发送消息是通过一系列的 send 和 post 方法来发送的,而 post 的一系列方法最终还是通过 send 实现的,发送一条消息的过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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 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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}

从上边可以发现,Handler 发送消息,实际上只是在消息队列中插入了一条消息。

MessageQueue 的 next 方法会将这条消息返回给 Looper ,最终这条消息由 Looper 交给 Handler 的 dispatchMessage 方法处理,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}

最后,调用 Handler 的 handlerMessage 方法来处理消息。