简单介绍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提供了以下方式来响应消息:

  1. 给Handler对象指定一个callback函数;
  2. 派生Handler类,重载Handler的handleMessage()函数;
  3. 给具体的消息捆绑一个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中创建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运行体内创建:

 final Thread thread2 = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                Handler甲 = new Handler(thread1.getlooper())
                {
                    @Override
                    public void handleMessage(Message msg)
                    {
                        if (msg.what == EVENT_JUST_FOR_TEST) {
                            this.getLooper().quit();
                        }
                        super.handleMessage(msg);
                    }
                };thread1.getlooper())
                {
                    @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进行了解。





 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值