Android源码阅读之MessageQueue

MessageQueue在消息机制中主要负责维护Message的链表结构,以及当有新Message进来时向Looper提供新Message,MessageQueue字义上看起来是消息队列的意思,但其数据结构其实是一个单链表的结构,从Message类的定义可以看出,里面有一个变量,指向了下一个Message

// sometimes we store linked lists of these things

/*package*/ Message next;

接下来,一起来看下MessageQueue中几个重要的方法

enqueueMessage

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) {

        if (mQuitting) {

            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;

}

此方法是将一个Message添加到Message链表中去,会先对message进行常规判断,message的handler是否为空,是否处于可使用的状态中,以及当前的消息机制是否被停止(由looper调用),当停止时,插入消息失败

接下来就是链表的插入操作,先判断是否存在表头,一开始mMessages是为空的,所以会将当前消息作为头部,mMessages作为当前消息的next

next()

next方法中是一个死循环 不断从消息链表中查询是否有可用状态的新消息加入,如果有,则返回给Looper

Message next() {

    // Return here if the message loop has already quit and been disposed.

    // This can happen if the application tries to restart a looper after quit

    // which is not supported.

    final long ptr = mPtr;

    if (ptr == 0) {

        return null;

    }

    int pendingIdleHandlerCount = -1; // -1 only during first iteration

    int nextPollTimeoutMillis = 0;

    for (;;) {

        if (nextPollTimeoutMillis != 0) {

            Binder.flushPendingCommands();

        }

        nativePollOnce(ptr, nextPollTimeoutMillis);

        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) {

                if (now < msg.when) {

                    // Next message is not ready.  Set a timeout to wake up when it is ready.

                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);

                } else {

                    // Got a message.

                    mBlocked = false;

                    if (prevMsg != null) {

                        prevMsg.next = msg.next;

                    } else {

                        mMessages = msg.next;

                    }

                    msg.next = null;

                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);

                    msg.markInUse();

                    return msg;

                }

            } else {

                // No more messages.

                nextPollTimeoutMillis = -1;

            }

            // Process the quit message now that all pending messages have been handled.

            if (mQuitting) {

                dispose();

                return null;

            }

            // If first time idle, then get the number of idlers to run.

            // Idle handles only run if the queue is empty or if the first message

            // in the queue (possibly a barrier) is due to be handled in the future.

            if (pendingIdleHandlerCount < 0

                    && (mMessages == null || now < mMessages.when)) {

                pendingIdleHandlerCount = mIdleHandlers.size();

            }

            if (pendingIdleHandlerCount <= 0) {

                // No idle handlers to run.  Loop and wait some more.

                mBlocked = true;

                continue;

            }

            if (mPendingIdleHandlers == null) {

                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];

            }

            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);

        }

        // Run the idle handlers.

        // We only ever reach this code block during the first iteration.

        for (int i = 0; i < pendingIdleHandlerCount; i++) {

            final IdleHandler idler = mPendingIdleHandlers[i];

            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;

            try {

                keep = idler.queueIdle();

            } catch (Throwable t) {

                Log.wtf(TAG, "IdleHandler threw exception", t);

            }

            if (!keep) {

                synchronized (this) {

                    mIdleHandlers.remove(idler);

                }

            }

        }

        // Reset the idle handler count to 0 so we do not run them again.

        pendingIdleHandlerCount = 0;

        // While calling an idle handler, a new message could have been delivered

        // so go back and look again for a pending message without waiting.

        nextPollTimeoutMillis = 0;

    }

}

这里看不太懂啊 搬运一下其他大佬的见解

获取消息:

1.首次进入循环nextPollTimeoutMillis=0,阻塞方法nativePollOnce(ptr, nextPollTimeoutMillis)会立即返回

2.读取列表中的消息,如果发现消息屏障,则跳过后面的同步消息,总之会通过当前时间,是否遇到屏障来返回符合条件的待处理消息

3.如果没有符合条件的消息,会处理一些不紧急的任务(IdleHandler),再次进入第一步

加入消息:

1.加入消息比较简单,按时间顺序插入到消息链表中,如果是第一个那么根据mBlocked判断是否需要唤醒线程,如果不是第一个一般情况下不需要唤醒(如果加入的消息是异步的需要另外判断)

到这里其实关于MessageQueue已经分析的差不多了,其中有两个native方法没有涉及到分别是nativePollOnce,nativeWake,其实之前结论已经给出了,两个方法都会传入mPtr,在native层对应的是NativeMessageQueue的引用地址。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值