1.前言
网络上关于Handler的介绍已经有太多了,
本文希望能图文并茂简单地介绍一下Handler,让大家更形象地理解并掌握Handler。
2.Handler是什么?
简单地说,Handler是 用来响应和处理消息的工具,所以才叫“Handler”。
例如,如果你想处理别人给你发的消息,通过Handler提供的方法填写你的响应代码就可以实现。
3.Handler都能干些什么?
通过Handler能干的事情:
1.让程序能响应消息;
2.让程序能发送消息;
3.让程序能删除消息;
为了让程序员用起来方便,体验爽快,在发送消息和响应消息上,有想方设法换不同花样进行封装接口。
例如:
1.发送的消息可以指定什么时间才被处理,比如sendMessageAtTime;
2.响应应消息的时候不关心消息值,只想随手写段代码等一下就能自动被调用,比如post(Runnable)。
3.1 响应消息
为了让程序员便捷地开发响应消息的代码,Handler提供了以下方式来响应消息:
给Handler对象指定一个callback函数;
派生Handler类,重载Handler的handleMessage()函数;
给具体的消息捆绑一个callback;
参考下面的“消息响应示意图”:
上图中,“消息处理代码1”就是第1中方式中对应callback函数体,所有“Handler丙”对应的消息被处理的时候都会调用“消息处理代码1”。
“消息处理代码2”就是第2中方式中对应的handleMessage()函数体,所有“Handler甲”的消息被处理的时候都会调用“消息处理代码2”。
“消息处理代码3”就是第3中方式中对应的callback响应函数体,只有“消息乙2”被处理的时候才会调用“消息处理代码3”(其实这个callback在实际编码中,形式是一个Runnable类实例,这个后面有介绍)。
为了更好地让大家了解以上方式的差异,接下来对这几种响应方式配合代码介绍一下。
3.1.1 给Handler对象指定一个callback函数
通过在指定的callback函数内编写响应消息的代码来处理消息,例如在构造函数提供一个callback,参考源码:
public class MyMessageCallback implements Handler.Callback // 自定义一个callback
{
public boolean handleMessage(Message msg)
{
switch (msg.what)
{
case EVENT_WIN_INIT:
do something
break;
}
return false;
}
}
Handler myMessageHandler =new Handler(new MyMessageCallback()); // 构造时候提供自定义的callback实例
从以上源码中可以看出,在构造的时候通过传入MyMessageCallback对象实例的方式来响应和处理消息。
3.1.2 派生Handler类,重载Handler的handleMessage()函数
通过在子类的handleMessage()函数内部编写响应消息的代码来处理消息,参考源码:
public class MyHandler extends Handler
{
public void handleMessage(Message msg) // 重载处理消息的函数
{
switch (msg.what){
case EVENT_WIN_INIT:
do something...
break;
}
}
}
从以上源码中可以看出,只需重载andleMessage()函数即可达到响应和处理消息的目标。对应以上代码,如果你想让它响应EVENT_WIN_INIT消息,那么你只需这样就行:
MyHandler handler = new MyHandler();
handler.sendEmptyMessage(EVENT_WIN_INIT);
3.1.3 给具体的消息捆绑一个callback
在发送具体某个消息的时候指定一个callback,待到消息被排队到处理的时候,将调用指定的callback。
这种方式的callback稍微有点特殊,通过程序提供一个Runnable对象实例来实现。例如post(myRunnable);
参考源码:
public class MyMessageCallback implements Runnable
{
public void run()
{
do something...
}
}
MyMessageCallback myMessageCallback = new MyMessageCallback();
handler.post(myMessageCallback);
以上代码,handler.post(myMessageCallback)调用后会在消息队列插入一个新消息,
这个新消息被处理的时候将会调用MyMessageCallback下的run函数。
3.2 发送消息
想要响应消息,必须有人使用Handler对象给你发送消息,
发送消息的本质,就是通过Handler对象往消息队列中插入消息。
参考插入消息示意图:
注意很重要的一点,别人给你发送消息用的handler对象必须和你用来响应消息的handler对象是同一个!
例如在“消息响应示意图”中,如果想在“Handler甲”里面响应消息,那么发送消息时候,必须使用“Handler甲”进行发送消息。
Handler中发送消息分为post和send两种,例如post(Runnable)、sendMessage(msg)。其实post和send本质上没有什么差异,仅仅是编码上的形式差异而已,通过不同的封装,让程序员在不同需求场合更为灵活和便捷地编写响应代码。
其中,post的方式一般是自己给自己发送消息,例如自己有段代码想过一会再执行,可以post的方式便捷地编写代码实现,参考下面代码:
Handler handler = new Handler();
handler.post(new Runnable()
{
@Override
public void run()
{
// "do something"
}
});
Handler发送消息的各个函数就不在此罗嗦,有需要的请查阅相关代码和资料。
3.3 移除消息
既然有插入消息,肯定有时候会遇到移除消息的情景。所以Handler也提供了从消息队列移除消息的功能函数,例如removeMessages()。
参考移除消息示意图:
注意,移除消息仅针对某个handler对象的,例如“Handler甲”只能移除自己插入的消息,不能移除“Handler乙”所插入的消息。
4.Handler和线程通信
本文前面就提到,Handler是 用来响应和处理消息的工具,这个说法其实是过于简略,因为文章刚开始并不想让大家牵涉太复杂的细节。
实际上,Handler的设计更重要的一个目的是让程序能简单地实现线程间通信。所以呢,Handler除了可以用来响应本线程的消息,也能响应其它线程发送过来的消息。
参考下面的“线程通过Handler通信示意图”:
图中,线程2通过访问“Handler甲”对象,发消息给线程1,
线程1收到消息处理的时候实际运行的代码“Handler甲”中的“消息处理代码”,
这段代码的运行实在线程1中发生的,如此,达到了线程2发消息给线程1的目的。
大概说起来就这么简单,实际操作编码的时候,要注意的两点:
*线程2如何能访问“Handler甲”对象
*“Handler甲”对象如何保证能在线程1中运行
规则:Handler关联哪个线程的消息队列,那么响应时候的处理代码就运行在对应的那个线程。
所以,为了保证“Handler甲”对象能在线程1中运行,“Handler甲”必须关联线程1的消息队列。
Handler怎么关联消息队列?
Handler对象关联消息队列的两种方法:
1.创建的时候自动关联所在线程的消息队列;
2.创建的时候指定某个线程的消息队列;
第1种方法,参考下面的代码,在线程1的运行代码中创建“Handler甲”,构造函数不传参数则自动关联线程1的消息队列:
final Thread thread1 = new Thread(new Runnable()
{
@Override
public void run()
{
createMessageQueue(); //伪代码:创建线程的消息队列...
// 在线程1中创建Handler甲,使得Handler甲操作的消息队列属于线程1的
Handler甲 = new Handler()
{
public void handleMessage(Message msg)
{
if (msg.what == EVENT_JUST_FOR_TEST) {
do something....
}
}
};
}
});
thread1.start();
从上面的代码可以看到,通过在线程1中“new Handler()”的方式创建了“Handler甲”,这样会自动和本线程的消息队列关联上,也就是“Handler甲”的操作都是针对线程1的消息队列。至于线程1的消息队列怎么来的,大家先别管,本文只介绍Handler。
第2种方法,创建Handler的时候必须指定线程1的消息循环进行关联,例如我们在线程2运行体内创建:
inal Thread thread2 = new Thread(new Runnable()
{
@Override
public void run()
{
Handler甲 = new Handler(<strong>thread1.getlooper()</strong>)
{
@Override
public void handleMessage(Message msg)
{
if (msg.what == EVENT_JUST_FOR_TEST) {
this.getLooper().quit();
}
super.handleMessage(msg);
}
};
以上代码,虽然我们线程2运行体内创建了“Handler甲”,但是“Hanlder甲”关联的线程1的消息队列,所以“Handler甲”的消息被处理的时候,实际上是在线程1中运行的。
结尾
Handler暂时介绍这么多,为了更好地理解Handler的作用,大家还需要对Looper、MessageQueue进行了解。
本文同时发布于:https://blog.csdn.net/henysugar/article/details/80271388