Hanlder源码分析(包括同步屏障,异步消息)

2019-01-04  本文已影响0人  koller

1 创建Handler

众所周知,在子线程直接创建Handler一定会报错,如图


1.png

意思也很明确,必须要调用Looper.prepare(),才能创建Handler,因为整个Handler的消息循环机制是建立在Looper之上.

那为什么主线程不用调用Looper.prepare就可以创建Handler呢?
因为在ActivityThread的main函数里面,帮我们调用了Looper.prepare()

public static void main(String[] args) {
        //省略部分代码
        ...
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

而使用两次Looper.prepare()则会报一下错误


2.png

因为每个Thread仅仅只能获取一个Looper.

搞清楚了Looper.prepare,我们来看一下为什么必须要调用它才能创建Handler.

2 Looper.prepare

3.png
4.png
5.png
6.png

而Looper的mQueue则是在构造函数中创建的,如图所示,即我们调用prepare的时候
到此,prepare的代码全部执行完了。

从上面的图6,可以看到prepare主要里是这句代码
sThreadLocal.set(new Looper(quitAllowed));
1 新建了一个Loopper对象
2 set到sThreadLocal里面
3 sThreadLocal又新建了一个Map来保存当前的key(即当前的Thread)与value(即新建的Looper)
4 Looper创建了MessageQueue

再来看new Handler做了什么事情

3 Handler构造函数

7.png

可以看到这句 mLooper = Looper.myLooper();关键代码,将Looper.myLooper赋值给Handler自己的mLooper,不然就报那个知名的错误。

mQueue = mLooper.mQueue;//将looper的mQueue赋值给Handler的mQueue

8.png
image.png

可以看到Looper.myLooper()是将prepare的里面创建的Looper再取出来。
可以得知 每次新建Handler的时候,得先将Looper创建好。

4 Looper.loop

一般我们创建好Handler之后,都需要在调用Looper.loop,我们看看它具体做了什么事情.

public static void loop() {
        final Looper me = myLooper();
        //省略部分无效代码
        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;
            }
          try {
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            //省略部分无效代码
            msg.recycleUnchecked();
        }
    }

至此,我们可以看到,loop是获取了,MessageQueue,然后启动死循环,不断调用queue.next直到消息队列里,没有任何消息了,才跳出循环.
至此,创建Handler的部分结束了,我们来看看Handler如何SendMessage的

5 Handler.SendMessage

当我们调用SendMessage时候,最终会调用的方法是这个


9.png
10.png
boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {// 如果是第一个进入到消息队列的消息且delay的时间最小(最小为0),则把其设置为消息队列的头
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
            //链表操作,增加一个消息实体
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {//根据delay的时间决定插在队列的什么位置
                        break;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }
        }
        return true;
    }

可以看到,MessageQueue.enqueueMessage会将所有的被sendMessage发送的Message增加到链表里。
由于Looper.loop的里面调用queue.next()的关系,(一直查询是否有新消息到来),如果查询到新消息,则进行msg.target.dispatchMessage(msg)。而msg的target则是在enqueueMessage做msg.target = this了,既当前发送此消息的Handler.
此时又回到了Handler的dispatchMessage

6 Handler.dispatchMessage

11.png

可以看到,dispatchMessage并没有做什么复杂的操作,仅仅就是判断了Message自身是否有CallBack,Handler是否设置了CallBack,如果都没有,则调用Handler的HandleMessage方法。

同步屏障

ViewRootImpl.java


 void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();//建立同步屏障
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); //发送消息
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

    void unscheduleTraversals() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
            mChoreographer.removeCallbacks(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        }
    }

Choreographer.postCallback实际上调用了postCallbackDelayedInternal,可以看到setAsynchronous(true);即设置为异步消息。

private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        if (DEBUG_FRAMES) {
            Log.d(TAG, "PostCallback: type=" + callbackType
                    + ", action=" + action + ", token=" + token
                    + ", delayMillis=" + delayMillis);
        }

        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);//设置为异步消息
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }

总结:
1 调用Looper.prepare是为了创建Looper,然后创建Map,根据CurrentThread保存Looper。Looper创建了MessageQueue
2 new Handler的时候会将Looper与Hanlder绑定,并且将Looper的MessageQueue与Handler的mQueue绑定
3 Looper.loop是为了启动消息循环不断查询(queue.next())是否有新消息到来,可能会阻塞
4 Handler.SendMessage则是将Message.target与Handler绑定,并且将Message插入到MessageQueue中去(根据delay插入,越小越前)
5 Looper.loop中查询到有新消息来了后,将会调用Message.target.dispatchMessage,将msg分发出去
6 Hanlder.dispatchMessage将进行msg的callback,Hanlder的callback判断,最后才调用HandleMessage.
即Message的CallBack优先级最高,Hanlder的CallBack其次,HandleMessage最低.
7 sThreadLocal是确保每个Thread里有且仅有一个Looper的关键,因为会去获取线程独有的ThreadLocal.ThreadLocalMap作为Map,然后把自己作为key,来保存looper,每次prepare则先会访问线程独有的ThreadLocal.ThreadLocalMap来判断是否有value
8 Message也分同步消息与异步消息,有两种方式发送异步消息, Message.setAsynchronous(True)与Hanlder.createAsync(),如果不设置则都为同步消息。在系统的ViewRootImpl里面Chreograher就是发送异步消息来绘制UI 即perfromTraversal会提前于所有同步消息执行
9 延时消息 是利用Message的when来对比,插入到哪里(小的前,大的后)

上一篇下一篇

猜你喜欢

热点阅读