美图欣赏 | 设为首页 | 加入收藏 | 网站地图

当前位置:电脑中国 > 编程 > 移动开发 >

Android基础夯实--你了解Handler有多少?

2018-01-08 13:58|来源:未知 |作者:dnzg |点击:

概述

对于刚入门的同学来说,往往都会对Handler比较迷茫,到底Handler是个什么样的东西。当然,可能对于一些有工作经验的工程师来说,他们也不一定能很准确地描述,我们来看下API的介绍。

Handler是用来结合线程的消息队列来发送、处理“Message对象”和“Runnable对象”的工具。每一个Handler实例之后会关联一个线程和该线程的消息队列。当你创建一个Handler的时候,从这时开始,它就会自动关联到所在的线程/消息队列,然后它就会陆续把Message/Runnalbe分发到消息队列,并在它们出队的时候处理掉。

从官方文档中,我们不难找出其中的关键词,就是“线程”。我们都知道,一个涉及到网络操作,耗时操作等的Android应用,都离不开多线程操作,然而,如果这时我们允许并发更新UI,那么最终导致控件的状态都是不可确定的。所以,我们可以通过对控件进行加锁,在不需要用时解锁,这是一个解决方案之一,但最后很容易造成线程阻塞,效率会非常差。所以,谷歌采用了只允许在主线程更新UI,所以作为线程通信桥梁的Handler也就应运而生了。

Looper、MessageQueue、Message、Handler的关系

讲到Handler,肯定离不开Looper、MessageQueue、Message这三者和Handler之间的关系,下面简略地带过,详细自己可以查阅相关资料,或者查看源码,这样更方便大家深入学习。

Looper

每一个线程只有一个Looper,每个线程在初始化Looper之后,然后Looper会维护好该线程的消息队列,用来存放Handler发送的Message,并处理消息队列出队的Message。它的特点是它跟它的线程是绑定的,处理消息也是在Looper所在的线程去处理,所以当我们在主线程创建Handler时,它就会跟主线程唯一的Looper绑定,从而我们使用Handler在子线程发消息时,最终也是在主线程处理,达到了异步的效果。

那么就会有人问,为什么我们使用Handler的时候从来都不需要创建Looper呢?这是因为在主线程中,ActivityThread默认会把Looper初始化好,prepare以后,当前线程就会变成一个Looper线程。

MessageQueue

MessageQueue是一个消息队列,用来存放Handler发送的消息。每个线程最多只有一个MessageQueue。MessageQueue通常都是由Looper来管理,而主线程创建时,会创建一个默认的Looper对象,而Looper对象的创建,将自动创建一个MessageQueue。其他非主线程,不会自动创建Looper。

Message

消息对象,就是MessageQueue里面存放的对象,一个MessageQueu可以包括多个Message。当我们需要发送一个Message时,我们一般不建议使用new Message()的形式来创建,更推荐使用Message.obtain()来获取Message实例,因为在Message类里面定义了一个消息池,当消息池里存在未使用的消息时,便返回,如果没有未使用的消息,则通过new的方式创建返回,所以使用Message.obtain()的方式来获取实例可以大大减少当有大量Message对象而产生的垃圾回收问题。

四者关系总体如下(如有不对的地方,谢谢指出)
image

Handler的主要用途

  1. 推送未来某个时间点将要执行的Message或者Runnable到消息队列。

  2. 在子线程把需要在另一个线程执行的操作加入到消息队列中去。

废话不多说,通过举例来说明Handler的两个主要用途。

1. 推送未来某个时间点将要执行的Message或者Runnable到消息队列

实例:通过Handler配合Message或者Runnable实现倒计时

  • 首先看一下效果图

image

  • 方法一,通过Handler + Message的方式实现倒计时。代码如下:

public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding mBinding;

    private Handler mHandler ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        //设置监听事件
        mBinding.clickBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //通过Handler + Message的方式实现倒计时
                for (int i = 1; i <= 10; i++) {
                    Message message = Message.obtain(mHandler);
                    message.what = 10 - i;
                    mHandler.sendMessageDelayed(message, 1000 * i); //通过延迟发送消息,每隔一秒发送一条消息
                }
            }
        });

        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                mBinding.time.setText(msg.what + "");   //在handleMessage中处理消息队列中的消息
            }
        };
    }
}

其实代码不用怎么解释,都比较通俗易懂,但是这里用到了DataBiding,可能没用过的同学看起来有点奇怪,但其实反而简略了代码,有一定基础的同学看起来都不会有太大压力,所以不做太多解释。通过这个小程序,作者希望大家可以了解到Handler的一个作用就是,在主线程中,可以通过Handler来处理一些有顺序的操作,让它们在固定的时间点被执行。

  • 方法二,通过Handler + Runnable的方式实现倒计时。代码如下:

public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding mBinding;
    private Handler mHandler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        //设置监听事件
        mBinding.clickBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                for (int i = 1; i <= 10; i++) {
                    final int fadedSecond = i;
                    //每延迟一秒,发送一个Runnable对象
                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            mBinding.time.setText((10 - fadedSecond) + "");
                        }
                    }, 1000 * i);
                }
            }
        });
    }
}

方法二也是通过代码让大家加深Handler处理有序事件的用途,之所以分开Runnable和Message两种方法来实现,是因为很多人都搞不清楚为什么Handler可以推送Runnable和Message两种对象。其实,无论Handler将Runnable还是Message加入MessageQueue,最终都只是将Message加入到MessageQueue。只要大家看一下源码就可以知道,Handler的post Runnable对象这个方法只是对post Message进行了一层封装,所以最终我们都是通过Handler推送了一个Message罢了,至于为什么会分开两种方法,下文会给大家详说究竟。下面再来看看Handler的第二个主要用途。

(责任编辑:dnzg)