前言

在Android 多线程场景中,存在主线程和子线程之分,主线程是应用程序首次启动时自动开启的,子线程由人为创建和开启。主线程不允许执行耗时任务,子线程不允许更新UI控件(多个线程并发操作UI控件存在线程不安全),所以当某些耗时任务执行后需要更新UI控件时,通常由子线程去执行耗时任务,然后再根据任务执行结果由主线程(又称UI线程)更新响应的UI控件。这其中,子线程与主线程之间通常使用Handler异步消息处理机制完成通信。

异步消息处理流程

Handler机制基本原理

Handler异步消息处理机制主要有4部分组成:Message,MessageQueue,Handler,Looper

  • Message:存储线程需要传递的信息的对象。Message可以携带少量信息,用于不同线程之间的数据交换。
  • MessageQueue:消息队列,先进先出,存储所有需要处理的消息。每个线程有一个MessageQueue。
  • Handler:消息处理者,有两个功能:(1)通过Handler.sendMessage()方法将消息发送到MessageQueue中存储;(2)通过Handler.handleMessage对接收到的消息进行处理。
  • Looper:MessageQueue管理者。每个线程只有一个Looper对象,通过死循环方式不断将MessageQueue中的消息取出,发送给对应的Handler处理。

UI控件更新中异步消息处理机制的整个流程如下图所示:首先主线程中创建Handler对象,并重写handleMessage()方法实现对不同消息的处理。然后子线程在需要更新UI时,调用并重写主线程创建的Handler对象的sendMessage()方法发送更新UI的消息。Handler将这些消息存放到MessageQueue中,Looper一直尝试从MessageQueue中取出消息,并回调dispatchMessage()方法发送给对应Handler的handleMessage()处理消息。

Handler机制详解

注意:在多线程通信中,一个线程只能有一个MessageQueue,对应一个Looper来管理,但一个线程可以创建多个Handler。当有多个Handler时,他们待处理的消息都会存放到这同一个MessageQueue中,Looper取出消息后,通过Message中的某些标识(Message.target)找到对应的Handler,然后将消息传给该Handler。上面的UI更新过程中,MessageQueue、Looper和Handler属于主线程,子线程只是调用主线程中的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
31
32
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
//主线程中创建Handler对象
private Handler handler = new Handler(){
//处理消息,在主线程中运行的
public void handleMessage(Message msg){
switch(msg.what){
case 0:
text.setText("更新UI");
break;
default:
break;
}
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
...
//子线程
new Thread(new Runnable(){
@Override
public void run(){
Message msg = new Message();
msg.what=0;
//发送消息
handler.sendMessage(msg);
}
}).start();

}
...
}

参考文章