Android开发中,Handler用的非常多,因为它和AsyncTask一样是系统提供给我们的异步的通信机制。能够将一些更新和别的不适合放在UI主线程的操作放到它们中去。
Handler的作用主要有两个:一是在线程中发送消息, 二是获取和处理消息。既可以发送消息sendEmptyMessage(int what) ,也可以发送指定的消息sendMessage(Message msg),还可以利用msg.obj的属性去传递我们需要的参数甚至对象,使原本的通信机制更为强大。
Handler发送消息的机制
Handler的出现,解决了在非UI主线程更新UI组件数据的问题。如上面提到的,我们使用handler.sendEmptyMessage(int what) 或者 sendMessage(Message msg)去发送消息,这个消息就会放去消息队列MessageQueue中,MessageQueue是个先进先出的队列,Handler按照这个顺序一直从消息队列MessageQueue中获取消息Message,并且按照约定的方式去处理这些消息。下面是最简单的发送空消息给handler去进行处理:
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg)
{
if(msg.what == 0x101)
{ //约定如何处理不同的msg消息
Log.i("print handler message", "msg.what = 0x101");
}
else if(msg.what == 0x201)
{
Log.i("print handler message", "msg.what = 0x201");
}
}
};
/**
* 发送空消息
*/
private void sendMessageA()
{
handler.sendEmptyMessage(0x101);
}
private void sendMessageB()
{
handler.sendEmptyMessage(0x201);
}
使用Handler的过程中,想必大家都会发现,如果在UI主线程中直接使用Handler去发送消息是没问题的,但放在非主线程中就会报错了。为什么呢?
Loop和MessageQueue的关系
这是因为非主线程中并不会自动创建Looper对象。Looper是顾名思义,是一个“圈”,负责管理消息队列MessgeQueue。Looper会不断(一直循环到队列中不再有message为止)从MessageQueue中读取消息并交给Handler去处理。因为我们在主线程中handler发送消息,主线程是自动帮我们初始化创建一个Looper对象的,而且每个线程只能有一个Looper。因为当然不允许同时有2个或以上的Looper对消息队列读取消息,这样就会导致类似“锁”的问题。也就是说,非UI主线程中,是不会自动帮我们创建这个Looper的。所以解决方法就是在发送消息前,先创建一个( prepare() ),然后开启它( loop() )。这样它才能正常的从消息队列中读取管理消息。
还是用上面的例子,不过改成在子线程中去创建Handler并且处理。
{
private Handler mHandler;
@Override
public void run() {
// 创建Looper
Looper.prepare();
mHandler = new Handler(){
@Override
public void handleMessage(Message msg)
{
if(msg.what == 0x101)
{ //约定如何处理不同的msg消息
Log.i("print handler message", "msg.what = 0x101");
}
else if(msg.what == 0x201)
{
Log.i("print handler message", "msg.what = 0x201");
}
}
};
//启动Looper,这样它才能从消息队列中读取管理消息
Looper.loop();
}
}
private void sendMessgeInThread()
{
MessageThread mThread = new MessageThread();
//创建Handler
mThread.start();
mThread.mHandler.sendEmptyMessage(0x101);
}
总结三者的关系
从上面分个的来说明,我们已经知道Handler,Looper和MessageQueue分别的作用是什么。这里就总结下它们三者的关系:
情况一,在主线程中
创建Handler ----> 使用handler发送消息 ---> 消息被放入消息队列MessageQueue中 ----> (主线程自动创建的)Looper负责不断地从消息队列中取出消息,交给Handler ---> Handler再次对不同的消息进行处理 ---> 消息message被处理完后,随即被扔弃毁掉,然后继续处理第二条到达的消息message,直到Looper已经将所有消息都读取完。
情况二,在非主线程中
在上面的基础上分别调用Looper.prepare() 和 Looper.loop()方法去创建和启动Looer。创建Handler前调用Looper.prepare() ,创建完毕使用Looper.loop()。 剩下的收发消息和处理消息的过程和情况一是一样的。