MessageQueue由Looper派发消息列表,不能够直接添加Message到MessageQueue,而是通过与Looper关联的Handler对象添加,可以使用Looper#myQueue()检索当前线程的MessageQueue.
总结
- MessageQueue消息队列,通过Handler调用enqueueMessage方法把Message添加到队列中,根据when循环遍历队列,并把消息放入指定的位置,校验是否需要唤醒线程。MessageQueue有一个消息屏障的概念,它本质上一个Message,与其不同的是Target==null,并且args是token,消息屏障的作用是过滤同步消息,拦截异步消息。
Looper在轮询时调用的是消息队列next方法,把Message传递给Looper,next方法首先黑判断队列中是否有消息屏障,如果有只发送异步消息,如果没有,就依次进行发送,当消息队列中没有Message时,next方法阻塞线程,等待新的消息到来,在阻塞线程之前,此方法会阻塞线程前,会执行IdleHandler,所谓的阻塞其实就是不断的轮询新的消息。
当调用quit方法是,mQuitting会变成true,MessageQueue将要被关闭,可以根据传递的参数safe选择是否安全的关闭,所谓安全的关闭是指,以当前的时间为节点,大于当前时间的Message会被删除小于当前时间节点的消息会被保留到执行完毕。而不安全的退出消息队列就是把整个mMessage设置为null。然后在looper轮询时next方法返回为null,通知looper消息队列已经关闭,Looper可以关闭了。
Handler线程里实际上有两个无限循环体,Looper循环体和MessageQueue循环体,真正阻塞的地方是在MessageQueue的next()方法里
变量 Message mMessages
在MessageQueue中所有的Message都是以链表的形式组织在一起的,mMessages保存了链表的第一个元素,也可以说是链表本身。
private long mPtr;
该变量用于保存native代码中MessageQueue的指针。mQuitAllowed
该变量用于标识消息队列是否可以被关闭,主线程的消息队列不可关闭。private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
当Handler线程处于空闲状态的时候(MessageQueue中没有其他Message时),可以利用它来处理一些事物,该变量就是用于保存这些在空闲时候要处理的事物。private IdleHandler[] mPendingIdleHandlers
用于保存将要被执行的IdleHandler。private boolean mQuitting
标识MessageQueue是否正在关闭。private boolean mBlocked
标识MessageQueue是否阻塞。private int mNextBarrierToken
在MessageQueue中有一个概念叫消息屏障,它用于拦截同步Message,阻止这些消息被执行,只有异步Message才会放行。消息屏障本身也是一个Message,只是它的target为null并且arg1用于区分不同的消息屏障,所以该变量就是用于不断累加生成不同的消息屏障。
构造
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
接受一个参数quitAllowed,表示消息队列是否允许退出。MessageQueue目前我发现在Looper构造的时候传递的。
而构造在Looper#prepare方法中和prepareMainLooper贴上代码
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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));
}
我们默认使用的MainLooper,但是也可以在自己去调用。
- isIdle()判断Looper是否空闲
/**
* Returns true if the looper has no pending messages which are due to be processed.
*
* <p>This method is safe to call from any thread.
*
* @return True if the looper is idle.
*/
public boolean isIdle() {
synchronized (this) {
final long now = SystemClock.uptimeMillis();
return mMessages == null || now < mMessages.when;
}
}
- IdleHandler addIdleHandler removeIdleHandler
IdleHandler是一个接口,用于在线程空闲时候处理一些业务。
queueIdle是接口内部的一个方法,返回Boolean值,当消息队列中的消息都处理完毕,就会调用这个方法,返回值为true时,IdleHandler会一直保持在消息队列中,,False则会执行完该方法后移除该IdleHandler。
需要注意的是,消息队列中还有其他延迟消息时,IdleHandler也会被调用,因为线程在此时是空闲的。
/**
* Callback interface for discovering when a thread is going to block
* waiting for more messages.
*/
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();
}
添加一个新的IdleHandler到MessageQueue中。当IdleHandler接口的回调方法queueIdle返回false时,该IdleHandler在被执行完毕后,立即自动删除,当然也可以调用removeIdleHandler来删除指定的IdleHandler。此方法在任何线程都是线程安全的。
/**
* Add a new {@link IdleHandler} to this message queue. This may be
* removed automatically for you by returning false from
* {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
* invoked, or explicitly removing it with {@link #removeIdleHandler}.
*
* <p>This method is safe to call from any thread.
*
* @param handler The IdleHandler to be added.
*/
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}
//从消息队列中移除一个之前添加的IdleHandler。如果该IdleHandler不存在,则不会发生任何事情。
/**
* Remove an {@link IdleHandler} from the queue that was previously added
* with {@link #addIdleHandler}. If the given object is not currently
* in the idle list, nothing is done.
*
* <p>This method is safe to call from any thread.
*
* @param handler The IdleHandler to be removed.
*/
public void removeIdleHandler(@NonNull IdleHandler handler) {
synchronized (this) {
mIdleHandlers.remove(handler);
}
}
- isPolling
/**
* Returns whether this looper's thread is currently polling for more work to do.
* This is a good signal that the loop is still alive rather than being stuck
* handling a callback. Note that this method is intrinsically racy, since the
* state of the loop can change before you get the result back.
*
* <p>This method is safe to call from any thread.
*
* @return True if the looper is currently polling for events.
* @hide
*/
public boolean isPolling() {
synchronized (this) {
return isPollingLocked();
}
}
private boolean isPollingLocked() {
// If the loop is quitting then it must not be idling.
// We can assume mPtr != 0 when mQuitting is false.
return !mQuitting && nativeIsPolling(mPtr);
}
返回当前线程的Looper是否正在轮询,此方法是安全的。
- addOnFileDescriptorEventListener
/**
* Adds a file descriptor listener to receive notification when file descriptor
* related events occur.
* <p>
* If the file descriptor has already been registered, the specified events
* and listener will replace any that were previously associated with it.
* It is not possible to set more than one listener per file descriptor.
* </p><p>
* It is important to always unregister the listener when the file descriptor
* is no longer of use.
* </p>
*
* @param fd The file descriptor for which a listener will be registered.
* @param events The set of events to receive: a combination of the
* {@link OnFileDescriptorEventListener#EVENT_INPUT},
* {@link OnFileDescriptorEventListener#EVENT_OUTPUT}, and
* {@link OnFileDescriptorEventListener#EVENT_ERROR} event masks. If the requested
* set of events is zero, then the listener is unregistered.
* @param listener The listener to invoke when file descriptor events occur.
*
* @see OnFileDescriptorEventListener
* @see #removeOnFileDescriptorEventListener
*/
public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
@OnFileDescriptorEventListener.Events int events,
@NonNull OnFileDescriptorEventListener listener) {
if (fd == null) {
throw new IllegalArgumentException("fd must not be null");
}
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
synchronized (this) {
updateOnFileDescriptorEventListenerLocked(fd, events, listener);
}
}
/**
* Removes a file descriptor listener.
* <p>
* This method does nothing if no listener has been registered for the
* specified file descriptor.
* </p>
*
* @param fd The file descriptor whose listener will be unregistered.
*
* @see OnFileDescriptorEventListener
* @see #addOnFileDescriptorEventListener
*/
public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
if (fd == null) {
throw new IllegalArgumentException("fd must not be null");
}
synchronized (this) {
updateOnFileDescriptorEventListenerLocked(fd, 0, null);
}
}
private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
OnFileDescriptorEventListener listener) {
final int fdNum = fd.getInt$();
int index = -1;
FileDescriptorRecord record = null;
if (mFileDescriptorRecords != null) {
index = mFileDescriptorRecords.indexOfKey(fdNum);
if (index >= 0) {
record = mFileDescriptorRecords.valueAt(index);
if (record != null && record.mEvents == events) {
return;
}
}
}
if (events != 0) {
events |= OnFileDescriptorEventListener.EVENT_ERROR;
if (record == null) {
if (mFileDescriptorRecords == null) {
mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
}
record = new FileDescriptorRecord(fd, events, listener);
mFileDescriptorRecords.put(fdNum, record);
} else {
record.mListener = listener;
record.mEvents = events;
record.mSeq += 1;
}
nativeSetFileDescriptorEvents(mPtr, fdNum, events);
} else if (record != null) {
record.mEvents = 0;
mFileDescriptorRecords.removeAt(index);
}
}
翻译:添加文件描述监听,当文件描述相关事件发生变化会接受到通知。
如果文件描述事件已经被注册,那么指定的Event和Listener会替换以前事件和监听。每个文件描述符不能指定多个监听。不需要文件描述监听,就把他注销掉removeOnFileDescriptorEventListener。
FileDescriptor 是“文件描述符”。
FileDescriptor 可以被用来表示开放文件、开放套接字等。
以FileDescriptor表示文件来说:当FileDescriptor表示某文件时,我们可以通俗的将FileDescriptor看成是该文件。但是,我们不能直接通过FileDescriptor对该文件进行操作;若需要通过FileDescriptor对该文件进行操作,则需要新创建FileDescriptor对应的FileOutputStream,再对文件进行操作
FileDescriptor相关文章
http://www.jianshu.com/p/430340c4a37a
http://www.jianshu.com/p/a2dc2907ec28
http://www.jianshu.com/p/837320d6faea
http://blog.csdn.net/yuanzhangmei1/article/details/9131971
目前还不知道addOnFileDescriptorEventListener是在哪里调用的,既然FileDescriptor也是做Io操作,肯定也是对文件操作
来看看 updateOnFileDescriptorEventListenerLocked方法,从移除监听可以看出来,event 是int值,如果传入0,代表移除监听。
这个方法让我蒙圈了,不管了 ,继续往下
/**
/**
* Returns the int descriptor. It's highly unlikely you should be calling this. Please discuss
* your needs with a libcore maintainer before using this method.
* @hide internal use only
*/
// Android-added.
public final int getInt$() {
return descriptor;
}
下面这段代码
int index = -1;
FileDescriptorRecord record = null;
if (mFileDescriptorRecords != null) {
index = mFileDescriptorRecords.indexOfKey(fdNum);
if (index >= 0) {
record = mFileDescriptorRecords.valueAt(index);
if (record != null && record.mEvents == events) {
return;
}
}
}
FileDescriptorRecord是存放监听,事件,文件描述符的实体类,根据getInt$的返回值作为键,去集合中找这个值,SparseArray看成是HashMap,1.如果真有且集合不为null,并且事件相同那就直接返回了。
if (events != 0) {
events |= OnFileDescriptorEventListener.EVENT_ERROR;
if (record == null) {
if (mFileDescriptorRecords == null) {
mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
}
record = new FileDescriptorRecord(fd, events, listener);
mFileDescriptorRecords.put(fdNum, record);
} else {
record.mListener = listener;
record.mEvents = events;
record.mSeq += 1;
}
nativeSetFileDescriptorEvents(mPtr, fdNum, events);
} else if (record != null) {
record.mEvents = 0;
mFileDescriptorRecords.removeAt(index);
}
这部分就很好理解,就是把FileDescriptorRecord对象以fdNum为键存进集合中。
- dispatchEvents
// Called from native code.
private int dispatchEvents(int fd, int events) {
// Get the file descriptor record and any state that might change.
final FileDescriptorRecord record;
final int oldWatchedEvents;
final OnFileDescriptorEventListener listener;
final int seq;
synchronized (this) {
record = mFileDescriptorRecords.get(fd);
if (record == null) {
return 0; // spurious, no listener registered
}
oldWatchedEvents = record.mEvents;
events &= oldWatchedEvents; // filter events based on current watched set
if (events == 0) {
return oldWatchedEvents; // spurious, watched events changed
}
listener = record.mListener;
seq = record.mSeq;
}
// Invoke the listener outside of the lock.
int newWatchedEvents = listener.onFileDescriptorEvents(
record.mDescriptor, events);
if (newWatchedEvents != 0) {
newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR;
}
// Update the file descriptor record if the listener changed the set of
// events to watch and the listener itself hasn't been updated since.
if (newWatchedEvents != oldWatchedEvents) {
synchronized (this) {
int index = mFileDescriptorRecords.indexOfKey(fd);
if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
&& record.mSeq == seq) {
record.mEvents = newWatchedEvents;
if (newWatchedEvents == 0) {
mFileDescriptorRecords.removeAt(index);
}
}
}
}
// Return the new set of events to watch for native code to take care of.
return newWatchedEvents;
}
这个方法由native调用
传递2个参数,int fd int events
第一行注释代码说明:获取文件描述符记录和可能更改的任何状态。
根据int 值,从集合取出对应的实体对象,如果对象=null,则返回0,代表没有监听,把对象的数据获取出来进行赋值运算,根据当前的事件过滤,()然后执行onFileDescriptorEvents方法,获取新的events事件。接下来就判断需不需要更新这个事件。
消息屏障
消息屏障也是一个Message,与其他消息不同的是消息屏障的Target=null,when=当前毫秒值,arg1是token,用于区分不同消息屏障,消息屏障的作用是拦截同步消息队列中的同步消息,放行异步消息。(在next方法中的do while中体现,只有消息屏障Target可以为空null,其他的Target为null直接抛异常了)
- 添加消息屏障到队列
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
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;
}
}
添加消息屏障到消息队列,when是当前时间执行点。arg1的值是token,消息屏障的唯一标识,值递增。final Message msg = Message.obtain();
这个msg就是消息屏障,它的Target是null。
断言when>0,p!=null,循环遍历消息队列,利用when进行比较,p.when只要小于when的都插入到队列前面.
m3 -- m2 --m1--m0
如果m3的when小于msg的when
m3 -- Barrier--m2--m1--m0
如果m3的when大于msg的when
Barrier--m3--m2--m1--m0
最后返回一个新的Token。
- 移除消息屏障
/**
* Removes a synchronization barrier.
*
* @param token The synchronization barrier token that was returned by
* {@link #postSyncBarrier}.
*
* @throws IllegalStateException if the barrier was not found.
*
* @hide
*/
public void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
// If the queue is no longer stalled by a barrier then wake it.
synchronized (this) {
Message prev = null;
Message p = mMessages;
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
prev.next = p.next;
needWake = false;
} else {
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;
}
p.recycleUnchecked();
// If the loop is quitting then it is already awake.
// We can assume mPtr != 0 when mQuitting is false.
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
删除消息屏障比较简单,遍历消息队列匹配token,在释放资源之前排列好队列。
重要方法 enqueueMessage
boolean enqueueMessage(Message msg, long when) {
//tartget不能为null,需要知道是那个Handler发送到消息队列,也是根据这个Target吧结果返回给指定的Handler
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//不能添加正在使用的Message到消息队列
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
//如果消息队列只能退出,不会接受Message,返回False,告诉Handler添加消息失败,并释放资源,把Message添加到回收池中。
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;
}
//标记Message正在使用,
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//如果消息队列没有Message,或者要添加的消息延时时间是0,或者需要加入到队列的Message时间节点小于链表第一个Message,都会把这个消息直接放入消息队列的头。
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.
//把msg插入到适合的位置,根据when,msg与p比较,把p插入msg的后面,msg插入prew的前面。prew最初是mMessage。
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插入到消息队列中,首先判断Target,其次是否在使用中,如果消息队列正在退出,则添加消息失败,释放资源。
在真正加添消息钱,把Message标记成正在使用。
消息添加到队列
- p==null 表示队列中没有消息,放入到列表头。
- when=0 表示此消息需要立即发送,直接加入到列表的头。
- 再此消息列表中,时间节点小于其他Message。
满足上面其中一种情况,Message直接加入MessageQueue中。
否则:
进入死循环,遍历Message,根据when找到合适的位置进行插入。(next获取下一个Message,如果下一个Message的when大于当钱msg的when,将msg.next赋值给Message,msg.next赋值给p.next,这样就行形成一个链表)
最后判断是否唤醒线程。native方法调用。返回true表示Message加入MessageQueue成功。
- 移除消息系列
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;
}
}
}
//移除所有未执行的Message。
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
/**
* 移除所有执行时间点在当前时间点之后的Message,而在当前时间点之前的Message会保留在消息队列中,
* 直到它们都被处理完为止。
*/
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {
removeAllMessagesLocked();
} else {
Message n;
for (;;) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
- removeMessages 上半部分
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
如果消息队列的头就有符合条件的Message,就从头开始删除符合条件的Message,并不断地更新mMessage的指向。
- removeMessages 后半部分
// 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;
}
到了这里前半部分没有满足,所以不会发生,不在需要关系指向问题,直接删除符合条件的Message。
从消息队列中删除Message的操作也是遍历消息队列然后删除所有符合条件的Message,但是这里有个小细节需要注意,从代码中可以看出删除Message分为两次操作,第一次是先判断符合删除条件的Message是不是从消息队列的头部就开始有了,这是时候会涉及到修改mMessages指向的问题,而mMessages代表的就是整个消息队列;在排除了第一种情况之后,剩下的就是继续遍历队列删除剩余的符合删除条件的Message。其他重载方法也是同样的操作,唯一的区别就是删除条件不同而已。
关闭消息队列
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(false)
这是一种强制关闭消息队列的方式,这种做法是不安全的方式,因为它会直接删除队列中所有未执行的Message,这一点可以从removeAllMessagesLocked()方法看出。
- quit(true)
安全关闭消息队列的方式,从removeAllFutureMessagesLocked()可以看出,这种方式会删除消息队列中所有还没有到达执行时间点的Message,而剩下的已经达到执行时间点的Message就会被保留,直到都被执行为止。
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;
}
//记录空闲时处理IdleHandler的数量
int pendingIdleHandlerCount = -1; // -1 only during first iteration
//阻塞线程时间 具体看下面
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
//释放可是释放的资源
Binder.flushPendingCommands();
}
//调用native方法来阻塞线程
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
// 需要操作的msg和需要进行比较的时间
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());
}
// 判断还有没有可用的Message
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 {
// 执行的时间到了
//重新排列Message
// 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.
// 没有Message了,可以睡觉了。
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
// 关闭消息队列,返回null,通知Looper停止循环
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.
// 第一次循环的空闲时候调用,所谓的空闲,指的是消息队列中没有Message了。
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
// 这里厉害了如果判断成立则说明没有IdleHandler和Message了,直接下次循环阻塞线程。
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
// 最小处理4个IdleHandler 具体看pendingIdleHandlerCount,如果只有2个呢?其他两个为Null?还是在其他什么地方调用,需要添加4个IdleHandler。主要还是看addIdleHandler方法在什么地方调用。
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.
//开始执行所有的IdleHandler,在根据返回的keep决定是否删除。
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.
//idle handler都执行完了,当然要初始化了
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.
//在处理idle handler的时候耗费了一些时间,也许又有其他的Message到达了呢,重置变量,重新检查消息队列。
nextPollTimeoutMillis = 0;
}
}
分开来写。还是写在代码上把。
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
mPtr是从native方法中得到的NativeMessageQueue地址
如果mPtr等于0说明队列不存在或被清除掉了
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
- pendingIdleHandlerCount
在空闲时需要处理IdleHandler的数量,只有第一次初始化的时候才能为-1。 - nextPollTimeoutMillis
通知native层阻塞线程
nextPollTimeoutMillis = -1 一直阻塞直到再次唤醒他
nextPollTimeoutMillis = 0 不阻塞线程
nextPollTimeoutMillis >0 阻塞线程多长时间
既然有阻塞线程,肯定也有唤醒线程,在enqueueMessage调用nativeWake(mPtr);唤醒线程。
接下来是一个死循环:
for(;;)
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
如果!=0,说明要阻塞线程了。为了长时间阻塞线程释放掉部分对象。
nativePollOnce(ptr, nextPollTimeoutMillis);
这个方法可厉害了,就是这个方法来阻塞线程的,根据指定的ptr来阻塞,nextPollTimeoutMillis在上面呢。
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
now以这个时间为基准开始比较,msg就是要发送给Looper的消息,主要看是如何对这两个Message进行操作的
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());
}
目前,msg是队列的头,也是当前的队列,Target为null,只有一种情况,那就是消息屏障。if判断队列的头是不是消息屏障。
- do while
不断地进行轮询,同步Message直接过滤,知道获取到第一个异步消息轮询结束。msg就是那个异步的Message,prevMes.next = msg;这里可以看的出来优先处理异步消息。过滤掉的消息不是指删除掉了,只是找到异步消息发送Looper,在下次循环的时候Message msg = mMessages;
只有发送的异步消息从队列移除了。
//重新排列Message
// 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();
// 把消息返回
如果prewMsg
- == null
执行的是同步消息,把mMessage这个消息队列重新赋值,next成了头。 - != null
代表执行的异步消息,也是重新排列队列。相当把异步消息移除。