Android MessageQueen详解

来源:互联网 发布:阿里云免费套餐9.9 编辑:程序博客网 时间:2024/06/05 02:57

MessageQueen是用来存放消息的,我们具体来看一下MessageQueen的运行机制。

具体描述如下:

Low level class holding the list of messages to be dispatched by a Looper. Messages are not added directly to a MessagreQueen,but rather throw MessageQueen.IdleHandler objects associated with Looper .you can retrieve the MessageQueen for the current thread with Looper.myQueen.

通过上述描述可知,MessageQueen是一个保存消息的低级类,其消息由Looper派发。消息并不是直接添加到MessageQueen当中的,而是通过与Looper对象关联的IdleHandler()添加的。通过调用Looper.myQueen可以获得当前消息所在的队列。

MessageQueen的成员变量有以下几个

Message mMessages;private final ArrayList<IdleHanlder> mIdleHandlers = new ArrayList<IdleHanlder>();private IdleHanlder[] mPendingIdleHandlers;private boolean mQuiting;boolean mQuitAllowed = true;private boolean mBlocked;private int mPtr;private native void nativeInit();private native void nativeDestroy();private native void nativePollOnce(int ptr,int timeoutMillis);private native void nativeWake(int ptr);
各个成员变量含义如下:

Message mMessage:一个Message实例,代表消息队列的头Head。

ArrayList<IdleHandler>:存放IdleHandler的数组。

mQuiting:表示当前队列是否处于正在退出的状态。

mQuitAllowed:表示当前队列是否允许退出。

mBlocked:判读队列是否阻塞等待一个非零超时的pollOnce。

mPtr:指向C/C++的指针,主要操作native函数。

上文提到了,Message并不是直接添加到MessageQueen中的,而是通过IdleHandler()接口添加的,那么我们看一下IdleHandler接口的定义

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();}/**      * Add a new IdleHandler to this message queue.  This may be      * removed automatically for you by returning false from      * IdleHandler queueIdle IdleHandler.queueIdle() when it is      * invoked, or explicitly removing it with removeIdleHandler.      */ public void addIdleHandler(IdleHandler handler){if(handler == null){throw new NullPointerException("Can't add a null IdleHandler");}synchronized(this){mIdleHandler.add(handler);}}/**      * Remove an IdleHandler from the queue that was previously added      * with addIdleHandler.  If the given object is not currently      * in the idle list, nothing is done.      */ public void removeIdleHandler(IdleHandler handler){synchronized(this){mIdleHandler.remove(handler);}}
当消息队列为空的时候调用IdleHandler接口,并且等待更多的消息。如果返回值为true,则保持当前IdleHandler是活跃的,否则移除当前IdleHandler。如果当前消息队列里面扔有消息,那么在消息执行完之后仍然会调用该接口。

通过addIdleHandler想MessageQueen添加一个IdleHandler,如果调用IdleHandler.queueIdle(),且返回值为false的时候,系统将自动移除该IdleHandler,或者直接调用removeIdleHandler来进行移除。这个方法是线程安全的。

看一个例子

final class myIdle implements MessageQueue.IdleHandler{@Overridepublic final boolean queueIdle(){doSomething();return false;}}
当MessageQueen中没有任何消息时,就会执行doSomething(),返回值为false,说明不保留该IdleHandler成员。

MessageQueen的构造方法(在Looper中调用)

MessageQueue(boolean quitAllowed){mQuitAllowed = quitAllowed;mPtr = nativeInit();}
MessageQueen的核心方法 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;        }    }
简单的说,这个函数就是从从头Head取出下一个Message,如果队列中没有message了,那么则可以取处理IdleHandler接口。当队列中没有消息或者消息指定了等待时间,那么线程会进入等待状态。

函数中有两个变量
int pendingIdleHandlerCount = -1;空闲的IdleHandler个数,只有在第一次迭代的时候为-1。

int nextPollTimeoutMillis = 0;下一轮等待时间,如果当前消息队列中没哟消息,需要等待的时间。

如果等待时间不为零,执行flush pending command,刷新等待时间。然后执行nativePollOnce(ptr, nextPollTimeoutMillis);其功能是查询消息队列中有没有消息。如果消息为空,那么nextPollTimeoutMillis=-1,接着等待消息,如果不为空,那么就处理这个消息。当我们设置的等待时间到了,将msg从Message中取出来并返回msg,如果没有返回,则说明没有消息需要处理,既然没有消息需要处理,检查以下是否要退出队列,如果退出返回null,否则那么就可以处理IdleHandler,处理完IdleHandler后将nextPollTimeoutMillis设为0(因为在处理IdleHandler的时候可能来消息),重新检测消息。

插入操作

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

如果msg正在使用或者msg对应的Handler为空或者不予许退出,则报异常。如果正在退出,则不允许进行插入操作,否则报异常。正常的插入操作类似于链表。当when=0或者when<p.when时插入表头。

删除

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

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






0 0