图文并茂深入浅出地话你知,Android的Handler究竟是怎么一回事?

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通信示意图”:

线程通过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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容