Android 谈谈Handler那些事

转载请注明出处
作者:DeveloperHaoz
本文链接:Android 谈谈Handler那些事

本文的主要内容
  • Handler是什么
  • Handler的两个体系
  • Message

一、Handler是什么

Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制,Handler直接继承自Object,每个Handler都关联了一个线程,每个线程内部都维护了一个消息队列MessageQueue,这样Handler实际上也就关联了一个消息队列。这样就可以通过Handler将Message和Runnable对象发送到该Handler所关联线程的MessageQueue(消息队列)中,然后该消息队列一直在循环拿出一个Message,对其进行处理,处理完之后拿出下一个Message,继续处理

Handler可以用来在多线程之间进行通信,在另一个线程中去更新UI线程中的UI控件只是Handler使用中的一种典型案例,除此之外,Handler还可以做其他很多的事情,Handler是Thread的代言人,是多线程之间通信的桥梁,通过Handler,我们可以在一个线程中控制另一个线程去做某些事

二、Handler的两个体系

Handler可以把一个Message对象或者Runnable对象压入到消息队列中,进而在UI线程中获取Message或者执行Runnable对象,Handler压入消息队列有两大体系,Post 和 sendMessage

  • **Post:**Post允许把一个Runnable对象入队到消息队列中,它的方法有:post(Runnable)、PostAtTime(Runnable, long)、postDelayed(Runnable, long)
  • **sendMessage:**sendMessage允许把一个包含消息数据的Message对象压入到消息队列中,它的方法有sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message, long)、sendMessageDelayed(Message, long)

从上面的各种方法可以看出,不管是post还是sendMessage都具有多种方法,它们可以设定Runnable对象和Message对象被入队到消息队列中,是立即执行还是延迟执行

1、Post

对于Handler的Post方式来说,它会传递一个Runnable对象到消息队列中,在这个Runnable对象中,重写run()方法,一般是在这个run()方法中写入需要在UI线程中的操作

在Handler中,关于Post方式的方法有

方法名称作用
boolean post(Runnable r)把一个Runnabled入队到消息队列中,UI线程从消息队列中取出这个对象后,立即执行
boolean postAtTime(Runnable r, long uptimeMills)把一个Runnable入队到消息队列中,UI线程从消息独立列中取出这个对象后,在特定的时间执行
boolean postDelayed(Runnable r, long delayMills)把一个Runnable入队到消息队列中,UI线程从消息队列中能够取出这个对象后,延迟delayMills秒执行
void removeCallbacks(Runnable r)从消息队列中移除一个Runnable对象

示例代码

public void onClick() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                  // 将TextView的内容进行修改
                    mTvShowInfo.setText("This is a test");
                }
            });
        }
    }).start();
}

有一点需要注意的是,对于Post方式而言,它其中的Runnable对象的run()方法的代码,均执行在UI线程上,所以如果是不能在UI线程上执行的操作,如网络请求之类的,一样无法使用Post方式执行

2、sendMessage

在Handler中,与Message发送消息相关的方法

方法作用
Message obtainMessage()获取一个Message对象
boolean sendMessage()发送一个Message对象到消息队列中,并在UI线程取到消息之后,立即执行
boolean sendMessageDelayed()发送一个Message对象到消息队列中,在UI线程取到消息后,延迟执行
boolean sendEmptyMessage(int what)发送一个空Message对象到消息队列中,并在UI线程取到消息之后,立即执行
boolean sendEmptyMessageDelayed(int what)发送一个空Message对象到消息队列中,并在UI线程取到消息之后,延迟执行
void removeMessage()从消息队列中移除一个未响应的消息

示例代码

        new Thread(new Runnable() {
            @Override
            public void run() {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        String testStr = "This is a test";
                        Message message = Message.obtain();
                        message.obj = testStr;
                        mHandler.sendMessage(message);
                    }
                });
            }
        }).start();
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == RESULT_OK_HANDLER) {
                String infoStr = (String)msg.obj;
                mHandlerTvShowInfo.setText(infoStr);
            }
        }
    };

三、Message

Handler如果使用sendMessage的方式把消息入队到消息队列中,需要传递一个Message对象,而在Handler,需要重写handleMessage()方法,用于获取工作线程中传递过来的消息,此方法运行在UI线程上

1、获取一个Message对象

一般并不推荐直接使用它的构造方法得到,而是建议通过Message.obtain()这个静态方法或者Handler.obtainMessage()获取。Message.obtain()会从消息池中获取一个Message对象,如果消息池是空的,才会使用构造方法实例化一个新的Message,这样有利用消息资源的重复利用,消息的上限为10个,Handler.obtainMessage()具有多个重载方法,查看源码可以知道,Handler.obtainMessage()在内部其实也是调用Message.obtain()

    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }
2、设置、获取和传递数据

Message是一个final类,所以不可被继承,Message封装了线程中传递过来的消息,如果对于一般的数据,Message提供了getData()和setData方法来获取和设置数据,其中操作的数据是一个Bundle对象,这个Bundle对象提供一系列的getXxx()和setXxx()方法用于传递基本数据类型的键值对,使用起来比较简单。

示例代码

new Thread(new Runnable() {
            @Override
            public void run() {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        String testStr = "This is a test";
                        Message message = Message.obtain();
                        Bundle testBundle = new Bundle();
                        testBundle.putString(KEY_STRING, testStr);
                        message.setData(testBundle);
                        message.what = RESULT_OK_HANDLER;
                        mHandler.sendMessage(message);
                    }
                });
            }
        }).start();
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == RESULT_OK_HANDLER) {
                String infoStr = msg.getData().getString(KEY_STRING);
                mHandlerTvShowInfo.setText(infoStr);
            }
        }
    };

而对于复杂的数据类型,如一个对象的传递就要相对复杂一些,在Bundle中提供了两个方法,专门用来传递对象的,但是这两个方法也有相应的限制,需要实现特定的接口,当然,一些Android自带的类,其实已经实现了这两个接口中的某一个,可以直接使用
- putParcelable(String key, Parcelable value):需要传递的对象类实现Parcelable接口
- putSerializable(String key, Serializable value):需要传递的对象类实现Serializable接口

还有另外一种方式在Message中传递对象,那就是使用Message自带的obj属性,它是一个Object类型,所以可以传递任意类型的对象,Message自带的还有如下几个属性

属性作用
int arg1参数一,用于传递不复杂的数据,复杂数据用setData()传递
int arg2参数二,用于传递不复杂的数据,复杂数据用setData()传递
Object obj传递一个任意的对象
Messaenger replyTo是作为线程通信的时候使用
int what定义的消息码,一般用于设定消息的标志,辨别究竟是从哪里中发来的消息

参考:
Android中Handler的使用
Android–多线程之Handler

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值