Handler系列之原理分析

上一节我们讲解了Handler的基本使用方法,也是平时大家用到的最多的使用方式。那么本节让我们来学习一下Handler的工作原理吧!!!

我们知道Android中我们只能在ui线程(主线程)更新ui信息,那么你们知道为什么只能通过Handler机制更新ui吗?其实最根本的目的就是解决多线程并发的问题。

假设在一个Activity中有多个线程去更新ui,并且都没有加锁,那么会是什么样子?

导致的结果就是更新界面错乱。

如果对更新ui的操作都进行加锁处理的话又产生什么问题哪?

性能下降。

处于对以上问题的考虑,Android给我们提供了一套更新ui的机制,我们只需要遵守这样的机制就可以了。根本不用去关心多线程问题,因为所有更新ui的操作,都是在主线程的消息队列当中通过轮训处理的。

<一>Handler机制的角色和职责

1 MessageQueue 消息队列

存储消息的容器,可以向其中添加、取出消息。遵循先进先出的原则。

2 Handler

负责将消息发向消息容器即MessageQueue中。

3 Looper 轮训器

通过调用自身的loop方法,不断的从消息队列当中取出消息并发送给target(即handler)处理消息。当消息队列当中没有轮训消息时,它就处于堵塞状态。

来个实际图来看一下Handler的工作原理:

Handler系列之原理分析

<二>Handler机制工作原理分析

Handler机制要想起作用有三个步骤:

1 创建Looper

2 创建Handler

3 调用Looper的loop方法,循环消息

下面让我们来看看android中,如何去遵循这三点的,在那之前,先普及一下一个知识:

默认整个应用程序,都是通过ActivityThread类启动的,在ActivityThread类当中,负责创建我们所有的Activity,并回调每个Activity中的生命周期方法。在ActivityThread类中,默认会去创建一个线程,这个线程叫做main线程(主线程)。所有的应用程序,更新ui的操作,都是在这个main线程中进行的。

创建Looper和调用loop方法的工作,Android SDK 已经为我们做好了,所以我们在平时使用的时候,只需要创建Handler并发送消息即可。下面我们跟随Android源码看看它是怎么做的。入口是ActivityThread的main方法。

Handler系列之原理分析

跟进Looper的prepareMainLooper方法

Handler系列之原理分析

跟进prepare方法

Handler系列之原理分析

这里我们需要对ThreadLocal类进行一下解释,ThreadLocal在我们的线程当中用于去保存一些变量信息,默认情况下,创建一个与线程相关的一个对象,是通过threadLocal存储的,threadLocal有set和get方法,set是把变量设置到threadLocal当中 ,get方法是获取出来。因为当前线程是ui线程,默认情况下threadLocal是没有存储的,所以为null,所以不走if而是new Looper对象之后在存储,下面我们在看看初始化Looper的时候做了哪些事情!

Handler系列之原理分析

我们看到,在创建Looper轮训器的时候,自动的创建了消息队列MessageQuene。也就是说默认的情况下,android为我们自动创建了主线程的Looper和MessageQuene。

那么Handler怎么和我们的MessageQuene消息队列联系在一起的那?因为之前不是说handler发出的消息是发送到消息队列中了吗?

原因还要看我们在创建Handler的时候做了那些事情,跟进Handler初始化源码发现最终调用的是下面这个构造器创建实例的。

    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
 final Class<? extends Handler> klass = getClass;
 if ((klass.isAnonymousClass || klass.isMemberClass || klass.isLocalClass) &&
 (klass.getModifiers & Modifier.STATIC) == 0) {
 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
 klass.getCanonicalName);
 }
        }

        mLooper = Looper.myLooper;
        if (mLooper == null) {
 throw new RuntimeException(
 "Can't create handler inside thread that has not called Looper.prepare");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

跟进Looper的myLooper方法

    public static @Nullable Looper myLooper {
        return sThreadLocal.get;
    }

看到了什么?sThreadLocal是不是很熟悉,没错它就是ThreadLocal对象。默认情况下android为我们创建了主线程Looper对象并存储在sThreadLocal中,所以此处返回的就是主线程的Looper对象,也就是说我们在创建Handler的时候,它就和消息队列关联起来了。

那么当我们使用handler发送消息的时候,不管使用哪一种方法,一步一步跟进源码发现最终调用的都是Handler的sendMessageAtTime方法

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
 RuntimeException e = new RuntimeException(
 this + " sendMessageAtTime called with no mQueue");
 Log.w("Looper", e.getMessage, e);
 return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

看代码可知,在发送消息的时候消息队列不能为null,继续跟进enqueueMessage方法

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
 msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

可以看到,消息最终发送到了消息队列当中。那么消息是怎么轮训的那?前面已经提过,是通过Looper的loop方法,那么来看看吧!!!

Handler系列之原理分析

可以看到loop方法里面的机制就是一个死循环,不断的从消息队列中取出消息,然后发送给target(handler对象)的dispatchMessage方法,跟进去!!!

Handler系列之原理分析

一般情况下我们发送消息的时候没有给Message的callback赋值,所以第一个if条件不满足。下面的mCallback是在我们初始化Handler的时候才被初始化,Handler初始化有一种方法Handler(Callback callback),此处的参数就是给mCallback赋值的。我们一般初始化Handler的时候使用的是空参数的构造器,所以导致mCallback未被初始化,所以会直接走handleMessage(msg)方法,也就是我们初始化Handler时重写的handleMessage方法。至此,Handler工作的机制就开始工作了,你、了解了吗?

下面让我们看看如果我们选择的是带Callback参数的初始化方式逻辑又会是什么样那,请看初始化代码:

    Handler mHandler = new Handler(new Handler.Callback {
        @Override
        public boolean handleMessage(Message msg) {
 Log.d(TAG,"callback参数-------handleMessage");
 return true;//此处的返回值会影响下面的handleMessage方法是否调用
 //false     调用
 //true      不调用
        } }){
        @Override
        public void handleMessage(Message msg) {
 Log.d(TAG,"重写handler的-------handleMessage方法");
 super.handleMessage(msg);

        }
    };

根据上面的源码分析我们知道此处Callback参数中的handleMessage方法的返回值会影响到下面第二个handleMessage方法是否调用。经过验证,return true 则不调用 ,return false则调用。

好了,Android中的Handler机制工作原理我已经介绍完毕!!!参考了幕课网中《Android面试常客Handler详解》,大家如果没有明白可以去该网站自行学习。下篇我将介绍如何在子线程创建Handler。

本文为头条号作者发布,不代表今日头条立场。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值