Handler源码解析

        Handler的工作流程

我们先从消息的发送和接收切入,也就是handler的工作流程。

如何往MessageQueue中放数据queue.enqueueMessage()

首先MessageQueue是数据结构是一个优先级队列

如何重MessageQueue中取数据呢?

        通过Looper.loop()方法从MessageQueue中循环的取,queue.next。

         从图中可以看出,当队列中没有message时,nextPollTimeoutMillis=-1,looper会一直休眠;那么当我们往队列中放入message时queue.enqueuemessage(),looper是不是应该起来干活了?

        这时在会调用queue.enqueuemessage()中的nativeWake(mPtr),把looper唤醒,起来干活了。

        这里就涉及到休眠和唤醒:nativePollOnce/NativeWake

        

Message next(){
    for(;;){
        ...
        // 阻塞
        nativePollOnce();
        ...
    }
}

//android_os_MessageQueue.cpp
static void android_os_MessageQueue_nativePollOnce(){
    NativeMessage * nativeMessageQueue = reinterpter_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->poolOnce();
}

void NativeMessageQueue::poolOnce(){
    ...
    mLooer->pollOnce(timeoutMillis)
    ...
}

//Looper.cpp
int Looper:pollOnce(timeoutMillis){
    ...
    result = pollInner(timeoutMillis)
}

int Looper::pollInner(timeoutMillis){
    ...
    // 就是这里利用epoll_wait(),进行阻塞等待,这里timeoutMillis表示阻塞时间
    int eventCount = epoll_wait(timeoutMillis)
    ...
    awake();
    ...
}

        

boolean enqueueMessage(Message msg,long when){
    ...
    //将消息放到队头
    if(needWake){
        // 唤醒
        natieWake(mPtr);
    }
}

// android_os_MessageQueue.cpp
static void android_os_MessageQueue(){
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast< NativeMessageQueue *>(ptr);
    nativeMessageQueue
}

void NativeMessageQueue::wake(){
    mLooper->wake();
}

void Looper::wake(){
    ...
    //往mWakeEventFd中 write 1,用以唤醒looper
    ssize_t mWrite = TEMP_FAILURE_READY(write(mWakeEventFd,...))
}

epoll是lINUX内核中的一种可扩展IO时间处理机制,大量应用程序请求时能够获得较好的性能。通俗点说:epoll会把哪个流发生了怎样的I/O时间通知我们,这样就避免了,如果有很多刘都没有数据,我们都要去循环遍历,浪费CPU。

Looper和线程是怎么样关联的呢?

 public static void prepare() {
        prepare(true);
    }

    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()方法ThreadLocal关联的,ThreadLocal就不再讲了,这样就保证了一个线程对应一个自己的Looper

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

通过handler的构造方法得知,一个Looper对应一个自己的MessageQueue。

 作为一个阻塞优先级队列MessageQueue,当多个Handler往MessageQueue中添加数据(发消息时,各个Hanlder可能处于不同的线程),那它的内部是如何确保线程安全的?

看源码可以得知,不论是enqueuemessage()还是next()方法,内部有synchronized内置锁,这样就保证了线程安全。

什么是synchronized?请看:深入理解并发编程和归纳总结_醉饮千觞不知愁的博客-优快云博客

 消息机制之同步屏障:

        MessageQueue是根据执行时间进行优先级排序的,然后消息保存在队列中,因而消息只能从队列的队头开始取,那么问题来了。万一有一个紧急消息来了怎么办?

        比如我们手机的UI刷新机制,也是用的Handler。

MessageQueue中有个postSyncBarrier()方法,给looper的消息队列中发送一个同步屏障。

private int postSyncBarrier(long when) {
        // Enqueue a new sync barrier token.
        // We don't need to wake the queue because the purpose of a barrier is to stall it.
        synchronized (this) {
            final int token = mNextBarrierToken++;
            final Message msg = Message.obtain();
            msg.markInUse();
            msg.when = when;
            msg.arg1 = token;

            Message prev = null;
            Message p = mMessages;
            if (when != 0) {
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
            }
            if (prev != null) { // invariant: p == prev.next
                msg.next = p;
                prev.next = msg;
            } else {
                msg.next = p;
                mMessages = msg;
            }
            return token;
        }
    }

注意上面的message给msg.target赋值,即msg.target==null 

        下面是ViewRootImpl和 Choreographer的代码:

// UI刷新
 void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            // 先给队列中发送一个同步屏障
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            // 然后发送一个异步消息
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

mChoreographer.postCallback->

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

       我们来看next()方法:

synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }

上面这段代码是这样的:

假如我们发现了一个消息屏障:if (msg != null && msg.target == null),我们就循环遍历找出

msg.isAsynchronous()=true的异步消息,return给loop中去。

拿到消息后就移出同步屏障。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值