Android的消息机制——Handle
1.Handle的定义、作用
Android中如果在子线程中更新UI会出现exception,对于界面来说是不安全的;
但是如果将耗时的操作放在主线程中,那么会导致界面加载比较耗时,对于一些加载数据耗时的操作,也会导致页面ANR(应用无响应);
所有为了可以在子线程中进行耗时的UI操作,可以使用Handle;
即:Handle是用来接收子线程发送的数据(消息),并且用此数据在主线程中进行UI更新;
通俗解释:
当应用程序(Application)启动时,Android首先会开启一个主线程即UI线程,UI线程会管理页面中的UI控件,进行控件的事件分发。
比如:点击一个button,button会有一个分发事件去响应click操作,但是如果此时需要一个耗时的操作(加载图片,读取数据等),而且将这些耗时的操作都放在主线程中话,在规定的时间内没有完成点击事件,应用会出现ANR无响应,出现错误提示强制关闭。但是如果将耗时操作放在子线程中,即在子线程中更新UI,因为子线程更新UI是不安全的,此时运行会出现异常。
Handle可以让主线程和子线程通过Message对象来传递数据,子线程sendMessage(包含数据),Handle把这些message对象放入主线程队列中,配合主线程进行UI更新。
2.Handle机制的原理
总共分为五步:
第一步:异步通信准备
在主线程中创建处理器对象(Looper)、消息队列对象(Message Queue)和Handle对象;
第二步:消息发送
非UI线程通过Handle发送消息(Message)到消息队列(Message queue)中
第三步:消息循环
消息出队:Looper循环取出消息队列(Message Queue)中的消息(Message);
消息分发:Looper将取出的消息(Message)发送给处理者(Handle);
第四步:消息处理
处理者(Handle)接受处理器(Looper)发送过来的消息(Message),根据消息(Message)进行UI更新操作。
Handler将Message发送到Looper的消息队列中,即MessageQueue,等待Looper的循环读取Message,处理Message,然后调用Message的target,即附属的Handler的dispatchMessage(),将该消息回调到handleMessage()中,然后完成更新UI操作。
3.代码示例
public class HandlerDemoActivity extends Activity {
private static final int MESSAGE = 1;
private Button button;
private Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
// 接受消息并且进行UI更新操作
if (msg.what == MESSAGE ) {
button.setBackgroundColor(Color.GREEN);
}
super.handleMessage(msg);
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
button = findViewById(R.id.handler_activity_bt);
// 子线程需要更新UI
new Thread() {
@Override
public void run() {
try {
Thread.sleep(500);
Message message = new Message();
message.what = MESSAGE;
handler.sendMessage(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
Q&A
1.子线程为什么不能更新UI?
https://www.jianshu.com/p/58c999d3ada7
2.主线程Looper.loop()里面为什么是死循环,会不会导致卡死,是不是特别消耗CPU资源?
线程是一段可执行的代码,当可执行的代码执行完成后,线程生命周期就终止了,但是对于主线程,我们不会希望当运行一段时间就退出了,所以采用死循环才能保证它不会被退出;
只有当有需要执行的消息时,主线程才将此消息取出来执行,否则进入休眠状态,释放CPU,所以不会导致卡死或者特别消耗CPU资源。
3.handle的源码解析
https://www.imooc.com/article/40380