Android Handler机制(二)—MessageQueue源码解析

MessageQueue

1.变量

    private final boolean mQuitAllowed;//表示MessageQueue是否允许退出
    @SuppressWarnings("unused")
    private long mPtr; //mPtr是native代码相关的

    Message mMessages; //表示消息队列的头Head
    private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
    private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
    private IdleHandler[] mPendingIdleHandlers;
    private boolean mQuitting;

    // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
    private boolean mBlocked;

    // The next barrier token.
    // Barriers are indicated by messages with a null target whose arg1 field carries the token.
    private int mNextBarrierToken; 

mQuitAllowed表示MessageQueue是否同意离,系统创造的UI线程的MessageQueue是无允的,其他客户端代码创建的都是同意的;

mPtr是native代码相关的,指向C/C++代码中的一点对象(指针),其他一些nativeXXX()相关的函数本文暂勿举行分析;

mMessages表示消息队列的头Head;

mIdleHandlers是IdldHandler接口的ArrayList,
mPendingIdleHandlers是数组版本,在末端的代码中见面拿ArrayList的情拷贝到它们里面;

mQuitting表示手上排是否处在正在离状态;

mBlocked表示next()调用是否被block在timeout不为0的pollOnce上;

mNextBarrierToken表示产一个barrier
token,barrier用target==null, arg1==token的Message对象表示;

IdleHandler callback接口:

public static interface IdleHandler {
        /**
         * Called when the message queue has run out of messages and will now
         * wait for more.  Return true to keep your idle handler active, false
         * to have it removed.  This may be called if there are still messages
         * pending in the queue, but they are all scheduled to be dispatched
         * after the current time.
         */
        boolean queueIdle();
    }
public void addIdleHandler(IdleHandler handler) {
        if (handler == null) {
            throw new NullPointerException("Can't add a null IdleHandler");
        }
        synchronized (this) {
            mIdleHandlers.add(handler);
        }
    }
 public void removeIdleHandler(IdleHandler handler) {
        synchronized (this) {
            mIdleHandlers.remove(handler);
        } 

IdleHandler接口表示当MessageQueue发现眼前没再次多消息可以拍卖的当儿虽然顺便干点别的事情的callback函数(即要发现idle了,

那么便摸索点别的事干)。callback函数有只boolean的返值,表示是否keep。如果回去false,则它见面于调用了后从mIdleHandlers

被移除。这里让咱们来拘禁一个具体的例子(实现),ActivityThread.java里之一个之中类,代码如下:

final class GcIdler implements MessageQueue.IdleHandler {
        @Override
        public final boolean queueIdle() {
            doGcIfNeeded();
            return false;
        }
    } 

即时是一个gc相关的IdleHandler,即只要没再次多的信可以处理便会抽空doGcIfNeeded(),最后回来false表示未保留在mIdleHandlers

遭到,即用平等软就是丢弃了,只实行同一普。

MQ的构造方法:在Looper中就是是调用的此构造方法。

MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;  //true是允许推出
        mPtr = nativeInit(); //这是一个本地方法
    }

MQ的构造方法简单的调用了nativeInit()来拓展初始化,这是一个jni方法,也就是说,可能是于JNI层维持了其这消息队列的靶子。在message中发生很多native方法,可以看出message是比较底层的一个看似。

连通下看MessageQueue的中坚措施,next()方法,如下:

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

先是初始化2个连片下去要因此到之变量,紧接着进入最for循环中,其某次循环主要做如此几件工作:

  1. 如果nextPollTimeoutMillis !=
    0的话,调用Binder.flushPendingCommands();

  2. 调用nativePollOnce(mPtr,
    nextPollTimeoutMillis);

3.
进来一个可怜之同步块,尝试获得一个好拍卖的音,具体做法是,记录时工夫now,初始化变量prevMsg为null,msg也mMessges;

倘msg是一个sync
barrier消息,则直奔下一个asynchronous消息(这里面的所有并消息会吃本次循环忽略,也就是说遇到这种场面,

next方法会从找到的异步消息的岗位上马尝试取一个足以拍卖的音信并返回),同时更新prevMsg,msg的值;

4.当退者do…while循环的时段msg可能吗空(走及队尾了),或者成功找到了一个这样的(异步)消息。

5.如果是至队尾了就算msg==null,则表示从来不还多之消息了,设置nextPollTimeoutMillis

-1;否则当now<msg.when(msg的日还没有到),设置一个成立之守候时,即调用

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

6.当msg到了拖欠处理的时日了,也就是说我们找到了这般一个音可以返回了,设置mBlocked为false,将msg从mMessages队列中得出来(类似单链表的去操作),并实施

msg.next=null、msg.markInUse(),返回msg。

7.如果到及时等同步了还没return的讲话,那说明还从来不可拍卖的音信,检查下阵是否要求退了,如果是实行dispose(),返回null。当Looper的loop方法来看null的message的时光会脱离loop。

8.接下来既然无信息可以拍卖,那即便该处理IdleHandler了。如果pendingIdleHandlerCount小于0(注意该以率先次跻身for循环是深受初始化为-1)且没有还多的信需要处理,设置pendingIdleHandlerCount=mIdleHandlers.size();

9.如果pendingIdleHandlerCount还是<=0的言语,表示并未idle
handler需要实行,

装mBlocked为true,接着进入下次轮回。

10.接下来便是依据mIdleHandlers来初始化mPendingIdleHandlers。退出并块后我们就是剩下最后一项事了,那即便是run
Idle
handlers。一个for循环用来开这就是工作,在循环外而IdleHandler没必要保留,则会起mIdleHandlers中移除。

11.
末重置pendingIdleHandlerCount为0(也便是4但见面在第一潮巡回的时段实施同样不良),将nextPollTimeoutMillis设为0,因为当我们以

执行4之当儿,新的Message可能已经来了,所以我们需要立即开始(不需等待)下次循环来检查。

**上面很丰富,简单点说不怕是:next方法取出下一个Message(从头部取),如果没Message可以处理,就可以拍卖下IdleHandler。

在押了了next()方法,接下我们来看enqueue()方法:

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

于后边介绍Handler的时刻,可以观看,许多暨message(包括runnable)相关的操作,最终都delegate给了MessageQueue的enqueue方法。

暨外措施同样,在enqueue之前,也都是针对参数msg的自我批评,比如msg如果在使用受到,或者msg的target是null,都见面抛出AndroidRuntimeException,进行扫尾条件检查后,会进来真正的拍卖逻辑。接下来的操作看似以平等布置单链表中插一个素:进入同步块

1.
要是这行列处于正在离的状态则不可知在朝着里入队了,不能够插入元素了,在这种气象下会抛出RuntimeException,然后return
false,

意味着失败了;

2.
连着下去表示队列的状态ok,设置msg的when字段,临时变量p指向队列头;(必要的初始化,准备干活)

3.
要是队列是空的要么when==0或when<p.when,也就是说要插入的之message应该以第一单职位吗就是是队首,那么她用凡新的Head,将它们跟本的序列连接起来;

4.
否则插入将发在队中的某某位置(有或是队尾),将msg插在率先个p的先头,p满足这个原则(p
== null || when < p.when)。

末了退出并块,返回true,表示操作(入队)成功。

**messageQueue中之要素是据顺序按时间顺序插入的(先实施的在前)。

removeMessages():

进而我们来拘禁3独八九不离十之removeMessages()方法,

 void removeMessages(Handler h, int what, Object object) {
        if (h == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            // Remove all messages at front.
            while (p != null && p.target == h && p.what == what
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }

            // Remove all messages after front.
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && n.what == what
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }

    void removeMessages(Handler h, Runnable r, Object object) {
        if (h == null || r == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            // Remove all messages at front.
            while (p != null && p.target == h && p.callback == r
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }

            // Remove all messages after front.
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && n.callback == r
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }

    void removeCallbacksAndMessages(Handler h, Object object) {
        if (h == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            // Remove all messages at front.
            while (p != null && p.target == h
                    && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }

            // Remove all messages after front.
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    } 

旋即3只措施才是remove的规格不同,其主逻辑都是同等之,即由队列中去除所有匹配的元素。总体构思都是先期打队首删除,如果去除了则队首

乘为连下去的要素,重复是进程,直到第一独无兼容的素出现。接着由之因素之后(after
front)开始查找并去,

术是链表删除后一个节点的艺术,即p.next=nn。注意这里还是抹所有匹配的音,而不是首先只门当户对的。

说到底看下阵的quit()方法:

void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }  

quit方法根据所传参数safe的价值,有2种不同的退出政策,如果是safe的淡出,则实行removeAllFutureMessagesLocked(),

夫中间的逻辑吗而队首的元素还不曾到期那说明队列中另外所有的因素也都无到,所以同样于删除所有的音讯就调用

removeAllMessagesLocked();否则遍历队列找到第一独p.when>now这样的message元素p,(更新队列的尾p.next=null,

缩编队列)从p开始一直到行列结束还是若叫删掉的元素,全部抹的;如果是unsafe的退,则具有message都一直为删并

回收即调用removeAllMessagesLocked()。

     
Message是链表结构,MessageQueue中的广大操作都是冲链表,看起困难的话语,可以画图,就不行清晰啦。。。

Message的源码分析:http://www.cnblogs.com/jycboy/p/5786551.html

 

MessageQueue源码解析:http://www.cnblogs.com/jycboy/p/5786682.html

 

Handler源码解析:http://www.cnblogs.com/jycboy/p/5791457.html

 

Message源码解析:http://www.cnblogs.com/jycboy/p/5786551.html

 

转车注明出处: http://www.cnblogs.com/jycboy/p/5786682.html