众所周知,在 Android 中,非 UI 线程中是不能更新 UI 的,如果在子线程中做 UI 相关操作,可能会出现程序崩溃。一般的做法是,创建一个 Message 对象,Handler 发送该 message,然后在 Handler 的 handleMessage() 方法中做 UI 相关操作,这样就成功实现了子线程切换到主线程。
概念
-
主线程:处理与UI相关的事件(如更新、操作等)
-
子线程:执行耗时操作(如网络请求、数据加载等)
-
Message(消息):需要被传递的消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,最终由Handler处理。
-
MessageQueue(消息队列):用来存放Handler发送过来的消息,内部通过单链表的数据结构(存储特点:先进先出)来维护消息列表,等待Looper的抽取。
-
Handler(处理者):负责Message的发送及处理。通过 Handler.sendMessage() 向消息池发送各种消息事件;通过 Handler.handleMessage() 处理相应的消息事件。
-
Looper(循环器):通过Looper.loop()不断地从MessageQueue中抽取Message,按分发机制将消息分发给目标处理者。
核心类方法介绍:

流程
Handler.sendMessage()发送消息时,会通过MessageQueue.enqueueMessage()向MessageQueue中添加一条消息;
通过Looper.loop()开启循环后,不断轮询调用MessageQueue.next();
调用目标Handler.dispatchMessage()去传递消息,目标Handler收到消息后调用Handler.handlerMessage()处理消息。
特别注意:
线程(Thread)、循环器(Looper)、处理者(Handler)之间的对应关系如下:
-
1个线程(Thread)只能绑定 1个循环器(Looper),但可以有多个处理者(Handler)
-
1个循环器(Looper) 可绑定多个处理者(Handler)
-
1个处理者(Handler) 只能绑定1个1个循环器(Looper)
使用
- 使用 Handler.sendMessage()
public class MainActivity extends AppCompatActivity {
private Button mButton;
private TextView mTextView;
// 步骤1:在主线程中 通过匿名内部类 创建Handler类对象
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
// 步骤5:根据不同线程发送过来的消息,执行不同的UI操作
if (msg.what == 1){
mTextView.setText("执行了线程的UI操作");
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = findViewById(R.id.textView);
mButton = findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 步骤2:创建所需的消息对象
Message msg = Message.obtain();
msg.what = 1; // 消息标识
msg.obj = "A"; // 消息内存存放
// 步骤3:在工作线程中 通过Handler发送消息到消息队列中
mHandler.sendMessage(msg);
}
}.start(); // 步骤4:开启工作线程(同时启动了Handler)
}
});
}
}
- 使用 Handler.post()
public class MainActivity extends AppCompatActivity {
private Button mButton;
private TextView mTextView;
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = findViewById(R.id.textView);
mButton = findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.post(new Runnable() {
@Override
public void run() {
mTextView.setText("执行了子线程的UI操作");
}
});
}
}.start();
}
});
}
}
网友评论