Handler源码分析

Handler的源码及工作流程已经是老生常谈了,是每个Androider必备的技能,今天我们也来分析一下

一、Handler

Handler我们一般用来进行“子线程进行耗时操作->更新UI”的操作,那么这样的操作是如何实现的呢,首先我们来看Handler的源码。首先从构造函数开始,我们可以看到有一个@hide标记的构造函数,这个我们不做分析,因为是给系统来做一些操作的,其他的全部都执行到这个构造函数:

	public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

传入一个Looper,通过这个Looper获取mQueue对象,然后再传入一个callback,这个callback是一个接口,里面有个handleMessage方法,很多时候这个参数为空,我们后面再进行分析,还有一个boolean值,先不管。

Looper是什么呢,看了类的介绍,可以看到是用来给一个线程做消息循环,mQueue是Looper里面的一个成员,类型是MessageQueue,是消息队列的意思。看一下mLooper在Handler中作用,发现只有一个getLooper方法真正用到了这个参数,说明这个Looper目前只是提供了一个消息队列。

接着看一下我们日常用来发送消息的方法,发现所有方法最终调用的都是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);
    }

意思是在某个特定的时间点,发送消息,最终调用的是enqueueMessage方法,也即将消息入队

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

首先设置message的target为当前handler,然后判断构造方法中传进来的boolean值,最后调用MessageQueue的入队方法,这里设置target是给消息分发的时候提供一个目标,否则系统不知道将消息发给谁,然后设置是否为异步操作,接下来进入消息队列。

二、MessageQueue

首先我们来分析一下MessageQueue,顾名思义,这是一个“消息队列”,首先来看一下构造函数

	MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

设置一个标志位,初始化一个long值,这个值是用native方法初始化的,看到这个值的注释,也说是给native层使用的,这里先不管,根据注释,前面标志位的意思是MessageQueue能否退出的意思。
接着分析Handler调用的那个方法

	boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
        	//如果没有target,抛出异常
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
        	//如果message正在被使用,抛出异常
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
            	//当MessageQueue quit调用之后,意味着Handler不存在了,或者线程死亡
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }
			//标记为正在使用
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

从这里我们可以看到,MessageQueue听起来是个队列,但其实是用链表来实现的,这里也就是将新建的Message放入链表的尾端。这里只是一个入栈操作,那么具体的执行是在什么地方呢,其实就是在用Looper实现

三、Looper

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));
    }

这个prepare依然是私有的,有两个方法调用

	public static void prepare() {
        prepare(true);
    }
	public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

第一个就是我们常用的方法了,第二个是给主线程提供一个Looper,prepare方法中首先获取sThreadLocal.get的指,ThreadLocal是线程私有的值,也就是说每个线程只需要一个,是唯一的,如果为空的话,直接新建一个Looper。

	private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

首先创建了一个消息队列,然后获取当前线程。

我们知道要在子线程使用Handler的话,必须要先调用Looper.prepare,然后再调用Looper.loop,也就是开启循环,prepara是准备Looper对象,这里我们看一下loop方法

	public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        ...
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
			...
            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;
			...
            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                ...
            }
	        ...
            msg.recycleUnchecked();
        }
    }

省略了部分代码,剩下的就是主要逻辑,首先获取Looper,为空的话直接抛出异常,然后获取消息队列,一个Looper对应一个消息队列,接下来就是一个死循环:获取MessageQueue的next消息,如果消息为空,直接返回进入下一次循环,然后根据时间调用 msg.target.dispatchMessage方法,这里的target也就是我们之前设置的Handler,即回调handler的dispatchMessage方法,一般我们处理消息也是在这个方法。这里MessageQueue的next方法比较重要,但是我们只是分析流程,这里不做分析,只需要知道是获取链表的下一个消息即可。再来看一下dispatchMessage方法

	public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

可以看到会首先判断message的callback属性,这个callback是一个Runnable对象,这个对象是在post方法里面,因为post方法传入的参数是Runnable,所以将Runnable通过getPostMessage®方法包装成了一个Message对象,所以就直接调用Runnable的run方法。在第二个判断里面,首先判断了mCallback是否为空,mCallback是在构造方法中传入的,是我们之前提过的Callback方法,如果不为空的话会先调用它的handleMessage方法。最后调用handleMessage方法,这个方法是一个空实现,不设计为抽象方法的原因是也有构造方法直接传入Runnable的情况,我们直接重写就可以。

也就是说,我们接收消息会有两种方式,可不是只有handleMessage一种。

分析到这里,基本流程已经清晰了,Handler负责消息的分发与处理,Message是消息的载体,MessageQueue是消息队列,用来保存需要处理的消息,Looper是管家,也就是负责消息的循环处理。

四、拓展

1、Message.obtain

一我们要发送消息,就要先创建消息,一般我们是用Message.obtain这个方法来获取

	public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

sPool这个参数只有在recycleUnchecked方法中才会赋值,也就是说message被回收之后,清除掉使用标记,作为对象再次返回,如果没有的话直接new一个。避免创建过多的对象

2、Looper死循环会阻塞主线程吗

因为Android是一个事件驱动的系统,主线程中要做的事都是以事件的形式发给主线程的Handler来处理,所以不会阻塞

3、内存泄漏问题

由于Handler持有Activity引用,而Activity退出的时候有时候消息还没处理完毕,导致内存泄漏,这种一般有两种方式解决:①、使用静态内部类+弱应用来解决,这样Activity退出之后,弱引用也随之释放,不会出现泄漏问题 ②、在onDestroy里面调用removeCallbacksAndMessages(null),即退出的时候清除掉所有消息队列里面的消息,这样也不会导致内存泄漏

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值