Handler Looper Messagequeue 间的关系

前言

出于性能考虑,Android 中的 UI 操作为非线程安全的,这意味着如果有多个线程并发操作 UI 组件,将会导致性能安全问题。为了解决这个问题,Android 制定了一条规则:只允许在 UI 线程中更新 UI。因此,Handler 类应运而生。

Handler 消息传递机制

Handler 类的主要作用有两个:

  1. 在新启动的线程中发送消息
  2. 在主线程中接收消息,获取消息中数据以更新 UI

原理

当新启动的线程发送消息的时候,消息会发送到与之关联的 MessageQueue 中,而 Handler 会不断地从 MessageQueue 中获取并处理消息–这会导致 Handler 类中处理消息的方法被回调。

下面是关于 Handler 的应用,每隔 1s 更新 TextView 上的时间。

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
34
35
public class MainActivity extends Activity{

private TextView textView;

static Handler handler = new Handler{
int count;
@Override
public void handleMessage(Message msg){
switch(msg.what){
case 1:
count++;
textView.setText(count + "")
break;
default:
break;
}
}
}

public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

textView = (TextView)findViewById(R.id.textView);

new Timer().schedule(new TimerTask(){
@Override
public void run(){
Message msg = Message.obtain();
msg.what = 1;
handler.sendMessage(msg);
}
}, 0, 1000);
}
}

这里要注意的是,TimerTask 对象的本质就是开启一条新的线程。

Handler Looper MessageQueue 的工作原理

先介绍一下与 Handler 一起工作的几个组件:

  1. Message: Handler 接收和处理消息的对象
  2. Looper: 每个线程只能拥有一个 Looper, 它的 loop 方法负责读取 MessageQueue 中的消息,读到消息之后就把消息发送给该消息的 Handler 进行处理。
  3. MessageQueue: 消息队列采用先进先出的方式管理消息。程序创建 Looper 对象时,会在它的构造器中创建 MessageQueue 对象。下面是 Looper 的构造函数源码:
1
2
3
4
5
private Looper(){
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}

该构造函数采用 private 修饰,表明我们无法通过构造器来创建 Looper 对象。从上面代码中可以看出,程序在初始化 Looper 对象时会创建一个与之关联的 MessageQueue。

另外,由于 MessageQueue 是由 Looper 对象负责管理的,也就是说,如果希望 Handler 正常工作,必须在当前线程中有一个 Looper 对象。

  1. 在主线程中,系统已经初始化了一个 Looper 对象,因此程序直接创建 Handler 对象即可,然后就可以通过 Handler 来发送 处理消息了。
  2. 在子线程中,必须自己创建一个 Looper 对象,并启动它。创建 Looper 对象调用它的 prepare 方法即可(prepare 方法保证每个线程最多只有一个 Looper 对象),然后调用 Looper 的静态 loop 方法来启动它。loop 方法使用一个死循环不断地从MessageQueue 中取消息,并将取出的消息分发给该消息对应的 Handler 处理。

归纳起来,Looper MessageQueue Handler 各自的作用如下:

  1. Looper: 每个线程只能拥有一个 Looper, 它的 loop 方法负责读取 MessageQueue 中的消息,读到消息之后就把消息发送给该消息所属的 Handler 进行处理。
  2. MessageQueue: 由 Looper 进行管理,它采用先进先出的方式管理 Message。
  3. Handler: 它把消息发送给 Looper 管理的 MessageQueue,并负责处理 Looper 分发给它的消息。

在子线程中使用 Handler 的步骤如下:

  1. 调用 Looper 对象的 prepare 方法为当前线程创建 Looper 对象。创建 Looper 对象时,它的构造器会创建与之配套的 MessageQueue。
  2. 有了 Looper 对象后,创建 Handler 类的实例,重写 handleMessage 方法,该方法负责处理来自于其它线程的消息。
  3. 调用 Looper 的 loop 方法启动 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
31
32
33
34
public class MainActivity extends Activity{

private MyThread myThread;

public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

myThread = new MyThread();
myThread.start();
}

//处理点击事件 发送消息
public void click(View view){
Message msg = Message.obtain();
msg.what = 6;
myThread.handler.sendMessage(msg);
}

class MyThread extends Thread{
public Handler handler;
@Override
public void run(){
Looper.prepare();
handler = new Handler(){
@Override
public void handleMessage(Message msg){
//处理消息事件
}
};
Looper.loop();
}
}
}