也来说说Handler消息机制

开篇

本文针对流程进行分析,不对源码涉入过深,如有不当,望不吝赐教。

协作图

先来看一张直观的协作流程图,通过此流程图,可以快速的在脑海中形成一个协作关系,本文的结构也是按照这流程图来进行描述。

Handler

常规操作

在我们项目中使用Handler可以说是非常的熟练,得益于Handler的多种构造方式,我们操作Handler可是相当简便,比如我们在Activity中的常规操作:


//1

private Handler handler=new Handler();



//2

    private Handler handler0=new Handler(new Handler.Callback() {

        @Override

        public boolean handleMessage(@NonNull Message message) {

        //....处理对应线程的消息,更新UI等

            //如果return true了,那么就不会再去执行Handler中的handleMessage(msg);

            return false;

        }

    });



    //3

    private Handler handler1= new Handler(){

        @Override

        public void handleMessage(@NonNull Message msg) {

        //....处理对应线程的消息,更新UI等

            super.handleMessage(msg);

        }

    };

紧接着,我们会使用上面构造出来的handler进行发送一个Message消息,最后我们会在上面的handleMessage callback中进行更新UI或者刷新一些信息。(这里笔者对于使用仅仅是一笔带过,不做过多讨论。)

构造函数

根据常用的创建Handler方式,首先来看看给我们提供的构造器

大体分为两大类:

  • 一类是不带looper参数,会默认获取当前线程的looper对象。

public Handler() {

        this(null, false);

    }



    public Handler(@Nullable Callback callback) {

        this(callback, false);

    }



    public Handler(boolean async) {

        this(null, async);

    }

上面的常用构建的Handler方式中,不带looper的public Handler (Handler.Callback callback),和public Handler()在Android API Level 30的版本中已经被打上@Deprecated标记

  • 一类是带looper对象参数,要求传入对应线程的looper对象;

public Handler(@NonNull Looper looper) {

        this(looper, null, false);

    }



    public Handler(@NonNull Looper looper, @Nullable Callback callback) {

        this(looper, callback, false);

    }

**但是值得注意的是:**当我们需要在子线程当中新建一个Handler时,如果我们也像在主线程中那样去操作,此时运行便会得到一个抛错:


"Can't create handler inside thread 'xxx' that has not called Looper.prepare()"

对于这个错误,我们也很熟练的能够解决,没错,听报错的,那就是call Looper.prepare();通常如下:


new Thread(new Runnable() {

            @Override

            public void run() {

                Looper.prepare();

                Handler mTHandler=new Handler();

                Message message=Message.obtain();

                message.arg1=1;

                mTHandler.sendMessage(message);

                //先记住,一定要有loop(),否则子线程中的消息并没有被处理

                Looper.loop();

            }

        }).start();

**为什么呢?**接下来我们就以这个进行切入点,来分析Handler消息机制。

  • 1、通过上面介绍的第一类构造函数新建的handler对象,都会将Handler中定义的成员变量:mLooper赋值=Looper.myLooper();从而获取到当前线程对应的looper对象。

  • 2、拿到的mLooper进行判空操作,如果是null,那么就会抛出一个运行时异常:xxx that has not called Looper.prepare()"。

  • 3、如果上面拿到的mLooper不为null,那么就往下走,将Handler中的成员变量mQueue(消息队列)赋值;mQueue=mLooper.mQueue;同时赋值callback与同步/异步标记位。

明显上面我们在子线程中进行new Handler时,并没有传入looper,那当然是会报错了,但是在activity中,我们不也是这么操作的吗,为何不抛同样的错误?那是因为在主线程中,应用程序启动时,便会在ActivityThread的Main方法中执行了同样的Looper.prepareMainLooper();故程序运行时检查,此时myLooper是不为空的。

Looper

先看上面步骤一:Looper.myLooper()

代码内容很简单,就是从threadlocal中返回当前线程的looper。return sThreadLocal.get();

接着上面的错误解决入口点:Looper.prepare();

最终都是调用到:


private static void prepare(boolean quitAllowed) {

        if (sThreadLocal.get() != null) {

            throw new RuntimeException("Only one Looper may be created per thread");

        }

        sThreadLocal.set(new Looper(quitAllowed));

    }

可以看到,会新建一个Looper对象,并且将其放入Threadlocal中,这个Threadlocal是个什么呢?线程本地变量,先记住:它很重要,就是它实现了线程的切换,实现了关联当前线程的looper。这样一来,在myLooper时获取到的looper就不为空了。

Looper.loop();

loop()是消息运转的关键,只有开启了loop才会处理入队的消息,当loop被调用,将会源源不断的从消息队列中取消息。

在这我以loop运作流程图代替直接上代码,以便清晰明了的理解loop。

MessageQueue

主要提供了消息入队和出队的方法,但是取消息并不是自己来取,而是交给了looper,当Looper开启了loop后,它就会去调用MessageQueue#next()方法,从而回到MessageQueue。

  • enqueueMessage 入队

  • next 出队

很重要的一点:MessageQueue消息队列的实现是Message链表结构的,直观的表示为:Message->Message->Message->null

消息的入队,是按照消息的时间when顺序来进行插入的,在调用enqueueMessage时,主要的步骤如下:

Message

定义了消息对象,消息成员变量,这篇文章暂不作分析。

相互持有关系

  • Handler中持有Looper,Looper#mQueue

  • Looper中持有MessageQueue亦即mQueue

  • Message中持有target->Handler

ThreadLocal

ThreadLocal在消息机制里面可以说非常的重要了,简单理解为:它实现了当前线程和属于当前线程的looper相关联,从而实现了线程的切换。

提供给开发者主要核心的方法

  • public void set(T value)

  • public T get()

写到此发现这套机制要写真的内容太多了,目前也只是先说说这一套大概流程。好了,今天的篇幅先到这吧,对于文中的MessageQueue、Message和ThreadLocal讲得很粗,先记住这几点的关系及协作流程,接下来会再深入进行分析。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值