前言
出于性能考虑,Android 中的 UI 操作为非线程安全的,这意味着如果有多个线程并发操作 UI 组件,将会导致性能安全问题。为了解决这个问题,Android 制定了一条规则:只允许在 UI 线程中更新 UI。因此,Handler 类应运而生。
Handler 消息传递机制
Handler 类的主要作用有两个:
- 在新启动的线程中发送消息
- 在主线程中接收消息,获取消息中数据以更新 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
35public class MainActivity extends Activity{
private TextView textView;
static Handler handler = new Handler{
int count;
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(){
public void run(){
Message msg = Message.obtain();
msg.what = 1;
handler.sendMessage(msg);
}
}, 0, 1000);
}
}
这里要注意的是,TimerTask 对象的本质就是开启一条新的线程。
Handler Looper MessageQueue 的工作原理
先介绍一下与 Handler 一起工作的几个组件:
- Message: Handler 接收和处理消息的对象
- Looper: 每个线程只能拥有一个 Looper, 它的 loop 方法负责读取 MessageQueue 中的消息,读到消息之后就把消息发送给该消息的 Handler 进行处理。
- MessageQueue: 消息队列采用先进先出的方式管理消息。程序创建 Looper 对象时,会在它的构造器中创建 MessageQueue 对象。下面是 Looper 的构造函数源码:
1 | private Looper(){ |
该构造函数采用 private 修饰,表明我们无法通过构造器来创建 Looper 对象。从上面代码中可以看出,程序在初始化 Looper 对象时会创建一个与之关联的 MessageQueue。
另外,由于 MessageQueue 是由 Looper 对象负责管理的,也就是说,如果希望 Handler 正常工作,必须在当前线程中有一个 Looper 对象。
- 在主线程中,系统已经初始化了一个 Looper 对象,因此程序直接创建 Handler 对象即可,然后就可以通过 Handler 来发送 处理消息了。
- 在子线程中,必须自己创建一个 Looper 对象,并启动它。创建 Looper 对象调用它的 prepare 方法即可(prepare 方法保证每个线程最多只有一个 Looper 对象),然后调用 Looper 的静态 loop 方法来启动它。loop 方法使用一个死循环不断地从MessageQueue 中取消息,并将取出的消息分发给该消息对应的 Handler 处理。
归纳起来,Looper MessageQueue Handler 各自的作用如下:
- Looper: 每个线程只能拥有一个 Looper, 它的 loop 方法负责读取 MessageQueue 中的消息,读到消息之后就把消息发送给该消息所属的 Handler 进行处理。
- MessageQueue: 由 Looper 进行管理,它采用先进先出的方式管理 Message。
- Handler: 它把消息发送给 Looper 管理的 MessageQueue,并负责处理 Looper 分发给它的消息。
在子线程中使用 Handler 的步骤如下:
- 调用 Looper 对象的 prepare 方法为当前线程创建 Looper 对象。创建 Looper 对象时,它的构造器会创建与之配套的 MessageQueue。
- 有了 Looper 对象后,创建 Handler 类的实例,重写 handleMessage 方法,该方法负责处理来自于其它线程的消息。
- 调用 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
34public 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;
public void run(){
Looper.prepare();
handler = new Handler(){
public void handleMessage(Message msg){
//处理消息事件
}
};
Looper.loop();
}
}
}