开门见山 解决问题
Handler是Android特有的用来异步地处理线程之间的消息传递问题的一个机制。Handler机制的本质是Android SDK 提供的一个工具类,它封装了Looper类、Message类、MessageQueue类、ThreadLocal类和一个CallBack内部接口。
使用Handler机制最主要的一个目的是为了更新UI,为了保证能让多个线程安全地并发操作主线程中的UI控件。
实例
我第一次接触Handler是在郭神的第二行代码第十章开篇,书中代码如下:
//主线程Activity内实现匿名内部类
private Handler mHandler = new Handler(){
public void handleMessage(Message msg){
switch (msg.what){
case 1:
//UI操作
break;
default:
break;
}
}
}
//同一Activity内子线程代码
@Override
public void onClick(View v){
switch(v.getID()){
case R.id.btn_change_UI:
new Thread(new Runnable(){
@Override
public void run(){
Thread.sleep(1000)//耗时操作
**Message mMessage = new Message();
mMessage.what = UPDATE_UI;
mHandler sendMessage(mMessage);**
}
}).start();
break;
default:
break;
}
}
}
上段代码中,在Activity中使用Handler匿名内部类并重写其handleMessage方法,该方法内通过获取传入Message的what变量,用switch实现不同的UI操作。
子线程中执行耗时操作后通过前文的mHandler对象,用sendMessage方法将处理后的Message实例对象发送出去。Message回到UI线程执行switch中相关的case的内容。
除了更新UI,Handler还能实现一些比较简单的小功能,比如实现再按一次返回键退出应用的功能。
private static boolean isExit = false;
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
isExit = false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
exit();
return false;
}
return super.onKeyDown(keyCode, event);
}
private void exit() {
if (!isExit) {
isExit = true;
Toast.makeText(getApplicationContext(), "再按一次退出程序",
Toast.LENGTH_SHORT).show();
// 利用handler延迟发送更改状态信息
mHandler.sendEmptyMessageDelayed(0, 2000);
} else {
finish();
System.exit(0);
}
}
}
当然,实现该功能有很多别的高效的办法,这里只是给出一种思路。
涉及的类
在开篇提到了Handler机制涉及Handler、Looper、Message、MessageQueue、ThreadLocal几个类。
类名 | 作用 | 包名 |
---|---|---|
Handler | 添加Message到MessageQueue 处理Looper分派的Message | android.os.Handler |
Looper | 获取MessageQueue内的Message 将Message分发给各个Handler对象 | android.os.Looper |
Message | 线程间通信的数据单元,存储通讯信息 | android.os.Message |
MessageQueue | 存储Handler发来的Message | android.os.MessageQueue |
ThreadLocal | 线程本地变量,用来存储当前线程信息 | java.lang.ThreadLocal< T > |
工作原理
Handler机制主要涉及如下流程:
- 异步通信准备:在主线程中创建Looper、MessageQueue、Handler对象
- 消息发送:子线程通过Handler对象发送Message到MessageQueue
- 消息循环:Looper从MessageQueue取出Message并分发给对应Handler
- 消息处理:Handler接收Message并根据Message中的信息进行相关操作
流程图如下:
需要注意的是:
- 一个Thread只能绑定一个Looper
- 一个Looper能绑定多个Handler
- 一个Handler只能绑定一个Looper
那么如何保证一个Thread只包含一个Looper对象呢?这就要提到ThreadLocal。
Looper 类下prepare方法用来给当前线程初始化一个looper,根据ThreadLocal内的信息,来判断是否需要new一个新的loope,源码如下:
// Looper.java
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}