用几个简短的例子将Handler相关的知识点整理下,方便以后查阅也方便大家快速掌握本知识点。
名词解释:
Message 是线程之间传递的消息,它可以在内部携带少量信息,用于在不同线程之间交换数据。
MessageQueue 是消息队列,它主要用于存放所有由 Handler发送过来的消息,这部分消息会一直在消息队列中,等待被处理。
Handler 即处理者,它主要用于发送和处理消息。发送消息一般使用 handler 的 sendMessage(),处理消息会调用 handleMessage()。
Looper 是每个线程中 MessageQueue的管家,调用 loop()方法后就会进入到一个无限循环当中,然后每当发现 MessageQueue中存在一条消息,就会将其取出,并传递到 handleMessage()方法当中。
注意:每个线程中只会有一个Looper对象,一个MessageQueue。Handler依附于创建时所在的线程。
下面就用代码示例其中的原理吧~
目标场景:
主线程向子线程发消息,子线程接收到主线程的消息后给主线程发个通知,然后主线程更新UI。
实现步骤:
1,主线程给子线程发消息,子线程接收消息。
既然是子线程接收消息,说明handleMessage是在子线程中。Handler是依附于子线程。代码如下:
private LoopThread loopThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
//开启实现了Runnable接口的子线程
new Thread(loopThread = new LoopThread()).start();
}
/**
* 通过实现Runnable接口的方式生成一个子线程
*/
public class LoopThread implements Runnable {
public Handler mHandler = null;
@Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
handleMsgAndTodo(msg);
}
};
Looper.loop();
}
}
一个实现了Runnable接口的子线程,在子线程中实例化了handler并通过handleMessage接收消息。注意此处有Looper.prepare();和 Looper.loop();说明是子线程自身新建的消息管家looper(主线程里默认建立了自己的looper)。
主线程发消息就可以直接调用”loopThread.mHandler.sendEmptyMessage(1);”(LoopThread是一个实现了Runnable接口的类)。
接下来子线程接受处理消息与主线程处理消息都封装handleMsgAndTodo(msg)方法中了。代码如下:
/**
* 对接收到的消息进行处理
* @param msg
*/
private void handleMsgAndTodo(Message msg) {
switch (msg.what) {
case 0:
showMessageTv.setText("2---这是更新后的UI");
Log.d("从子线程发消息到主线程", "接收成功");
break;
case 1:
Log.d("从主线程发消息到子线程", "接收成功");
handler.sendEmptyMessage(0);
Log.d("从子线程发消息到主线程", "准备发送");
break;
default:
break;
}
}
刚刚主线程发的消息msg.what = 1,这里接收到消息立即给主线程发消息msg.what = 0,注意用的是handler而不是mHandler或者loopThread.mHandler,这里的handler是在主线程中实例化。代码如下:
/**
* 接收异步消息更新UI
*/
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
handleMsgAndTodo(msg);
}
};
此处的handler是依附于主线程的,可以直接在其中更新UI。
另外,还有几个方法也是基于异步消息机制。
比如在子线程中更新UI的例子:
/**
* 调用hander.post()方法更新主线程UI
*/
private void handerpost() {
new Thread(new Runnable() {
@Override
public void run() {
//...省略进行的耗时操作代码,以下三种方法实现子线程给主线程发消息
// handler.sendEmptyMessage(0);
//这几个方法在子线程中更新UI等效于在主线程中调用handleMessage()更新UI——hander.post(),view.post(), runOnUiThread(),其原理都是通过异步消息处理机制实现的。
// handler.post(new Runnable() {
// @Override
// public void run() {
// showMessageTv.setText("1---这是更新后的UI");
// }
// });
//在子线程中new Handler(Looper.getMainLooper())就表示其handleMessage()方法里的事情是在主UI线程去处理的,这个Handler其实是与主线程绑定的。
Handler handler2 = new Handler(getMainLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
showMessageTv.setText("3---这是更新后的UI");
}
};
handler2.sendEmptyMessage(0);
}
}).start();
}
如上几段代码中的方法,无异于都是调用主线程中的handler进行发消息更新UI。另一个在子线程中实例化的handler2,也是因为共用了主线程的looper,即与主线程维护同一个消息队列,所以相当于在主线程更新UI。
自我理解:
哪个线程要接收消息,就在该线程实例化Handler来调用handleMessage。若主线程向子线程发消息,则需要用到 Looper.prepare()和 Looper.loop(),并在子线程中实例化Handler来调用handleMessage()。
在子线程中new Handler(Looper.getMainLooper())就表示其handleMessage()方法里的事情是在主UI线程去处理的,这个Handler其实是与主线程绑定的。
hander.post(),view.post(), runOnUiThread()这几个方法在子线程中更新UI等效于在主线程中调用handleMessage更新UI——其原理都是通过异步消息处理机制实现的。
Handler+Thread与HandlerThread区别:
HandlerThread就是将含有消息队列的Looper与Thread封装在一起的写法,可以直接在子线程的接受的消息处理耗时任务。
Handler+Thread与 AsyncTask优缺点:
1,AsyncTask,是Android提供的轻量级的异步类,直接继承AsyncTask类进行异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.
使用的优点:简单,快捷(只是代码上轻量一些,而实际上要比handler更耗资源),过程可控
使用的缺点:在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.
2,Handler+Thread
结构清晰,功能定义明确
对于多个后台任务时,简单,清晰
使用的缺点:在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)