Android-Handler源码解析-MessageQueue

Android-Handler源码解析-MessageQueue

成员变量

// Log的Tag
private static final String TAG = "MessageQueue";
// 是否是Debug
private static final boolean DEBUG = false;

// 此消息队列是否可以退出,true为可以退出。
@UnsupportedAppUsage
private final boolean mQuitAllowed;

// natvie 层的消息队列的标识
@UnsupportedAppUsage
private long mPtr; // used by native code

// 此消息队列的头元素
@UnsupportedAppUsage
Message mMessages;
// 此消息队列的所有IdleHandler
@UnsupportedAppUsage
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
// 用于记录文件描述符
private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
// 
private IdleHandler[] mPendingIdleHandlers;
// 此消息队列是否退出
private boolean mQuitting;

// 此消息队列是否是阻塞的
private boolean mBlocked;

// 下一个屏障token。
// 障碍由带有空target的消息表示,其arg1字段携带token。
@UnsupportedAppUsagejava
private int mNextBarrierToken;
复制代码

说明:

  1. MessageQueue为什么需要持有Message,因为MessageQueueMessage集合。
  2. Message相关介绍,请看三方库-Handler源码解析-Message

创建MessageQueue

想要使用MessageQueue,首先需要创建MessageQueue,所以我们接下来看下它是如何被创建的。

new MessageQueue()

MessageQueue类

MessageQueue(boolean quitAllowed) {
	// 记录是否允许退出
    mQuitAllowed = quitAllowed;
    // 初始化native层的消息队列,并记录其返回指针。
    mPtr = nativeInit();
}
复制代码

MessageQueue构造方法,为默认的,只能同包下调用,目前只有Looper创建时调用了,我们来看下Looper的创建。

Looper构造方法

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed); // 创建消息队列
    mThread = Thread.currentThread();
}
复制代码

创建Looper,可以通过Looper.prepare()方法创建非主线程Looper,它是允许退出的;可以通过Looper.prepareMainLooper()方法创建主线程Looper,它是不允许退出的。

说明:

  1. Looper创建相关介绍,请看三方库-Handler源码解析-Looper-创建Looper

小结

  1. MessageQueue的创建,只能通过Looper进行创建。主线程Looper,它是不允许退出的;非主线程Looper,它是允许退出的。

加入Message

当通过Handler发送消息的时候,最终会调用MessageQueueenqueueMessage()方法,我们来看一下。

Handler->enqueueMessage()

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
    msg.target = this;
    msg.workSourceUid = ThreadLocalWorkSource.getUid();

    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    // 调用MessageQueue的enqueueMessage()方法加入消息
    return queue.enqueueMessage(msg, uptimeMillis);
}
复制代码

Handler发送消息的时候,最终都会走到HandlerenqueueMessage()方法,最终都是调用MessageQueueenqueueMessage()方法进行加入。

说明:

  1. Handler发送消息相关介绍,请看三方库-Handler源码解析-Handler-发送Message

接下来,我们来看下MessageQueueenqueueMessage()方法。

enqueueMessage()

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
	    // 消息的目标Handler为空,抛出异常。
        throw new IllegalArgumentException("Message must have a target.");
    }
	// 加锁,保证线程安全,因为加入Message操作(handler.send/post)可以在任何线程调用。
    synchronized (this) {
        if (msg.isInUse()) {
	        // 消息正在用(未被回收),再用则抛出异常。
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        if (mQuitting) {
	        // 退出中,再加入,则Log警告提示,并回收消息。
            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; // 更新消息的when时间
        Message p = mMessages; // 当前消息,默认为消息队列的Head元素。
        boolean needWake; // 是否需要唤醒线程
        if (p == null || when == 0 || when < p.when) {
            // 新的头,将Message插入到队首,如果阻塞,则唤醒事件队列。
            // 说明:
            // p == null,说明头为空,队列为空。
            // when == 0,说明需要排在队列前面(handler.sendMessageAtFrontOfQueue()方法调用传入)。
            // when < p.when,说明此Message的执行时刻比Head的早,所以要将Message插入到队首。
            
            msg.next = p; // 此Message链接Head(将此Message插入到队首)
            mMessages = msg; // Head为此Message
            needWake = mBlocked; // 如果阻塞,则唤醒。
        } else {            
            // 队列有数据,并且非强制排在前面,并且此Message的执行时刻比Head的晚,将Message插入到队列中间。
            // 通常我们不需要唤醒事件队列,除非在队列的头部有一个屏障,并且消息(msg)是队列中最早的异步消息。
			
			// 阻塞,并且是头是屏障消息,并且是头是屏障消息,并且消息(msg)是异步消息,则先为唤醒。
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev; // 上一个元素
            // 遍历队列,找到 Message 目标插入位置
            for (;;) {
                prev = p; // 上一个元素等于当前元素
                p = p.next; // 当前元素等于下个元素,方便下次循环。
                if (p == null || when < p.when) {
                    // 找到位置,退出循环。
					// 说明:
		            // p == null,说明下个元素为空,到队尾了。
		            // when < p.when,说明此Message的执行时刻比下个元素的早;又因为走的是此else逻辑,所以此Message的执行时刻比上个元素的早,所以要将Message插入到此位置。
                    break;
                }
                if (needWake && p.isAsynchronous()) {
	                // 需要唤醒,并且下个消息是异步消息,即消息(msg)不是队列中最早的异步消息,则不需要唤醒。
                    needWake = false;
                }
            }
            // 将Message插入队列的目标位置
            msg.next = p;
            prev.next = msg;
        }

        // 是否需要唤醒Native侧的MessageQueue
        if (needWake) {
	        // 唤醒
            nativeWake(mPtr);
        }
    }
    return true;
}
复制代码

enqueueMessage()方法,为向此消息队列加入消息

说明:

  1. Looper退出后,再向MessageQueue加入消息不再加入,并返回false
  2. 加入消息默认是按Messagewhat升序进行加入除非调用handler.sendMessageAtFrontOfQueue()方法强制将消息加入消息队列顶部
  3. 加入消息,需要判断是否需要唤醒,因为此线程之前可能进入阻塞再加入消息,应该唤醒然后执行此消息。

小结

获取Message

next()

@UnsupportedAppUsage
Message next() {
    // 如果消息loop已经退出并被销毁,则返回此处。
	// 如果应用程序在退出后尝试重新启动looper,则可能会发生这种情况,这是不受支持的。
    final long ptr = mPtr;
    if (ptr == 0) {
	    // mPtr为0,说明loop已经退出了,直接返回null。
        return null;
    }

	// 待处理的IdleHandler的数量,为-1代表是第一次初始化的状态。
    int pendingIdleHandlerCount = -1;
    // 下一次Poll超时时间,nativePollOnce()方法用。
    int nextPollTimeoutMillis = 0;
    // 开启循环
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
		
        // 阻塞方法,根据nextPollTimeoutMillis判断是否要阻塞。
        // nextPollTimeoutMillis=-1,一直阻塞,不会超时。
        // nextPollTimeoutMillis=0,不会阻塞,立即返回。
        // nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis毫秒,如果期间有程序唤醒会立即返回。
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            // 尝试检索下一条消息。如果发现则返回。
            final long now = SystemClock.uptimeMillis(); // 当前时间
            Message prevMsg = null; // 上一个消息
            Message msg = mMessages; // 当前消息,默认为Head。
            if (msg != null && msg.target == null) {
                // 队首是屏障消息,的话被屏障阻挡。在队列中查找下一个异步Message。
                // 说明:同步屏障只允许异步消息通过,所以得找到下一个异步Message。
                
                // 使用do-while先获取到下一个数据,然后再判断,因为当前消息为屏障消息。
                do {
                    prevMsg = msg; // 前一个为当前
                    msg = msg.next; // 当前的为下一个,以便循环。
                } while (msg != null && !msg.isAsynchronous()); // 消息不为空,并且消息是同步,全部过滤掉。
            }
            if (msg != null) {
	            // 有更多消息,判断是否到达执行时刻。
                if (now < msg.when) {
                    // 未到达执行时刻。设置一个阻塞时间,以便在它到达时唤醒。
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 到达执行时刻,返回消息。
                    mBlocked = false; // 不阻塞状态
                    // Message出队
                    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 {
                // 无更多消息,让其一直阻塞。
                nextPollTimeoutMillis = -1;
            }

            // 在处理了所有挂起的消息之后,处理退出消息。
            if (mQuitting) {
	            // 正在退出,返回null,以结束Looper.loop()。
                dispose();
                return null;
            }            
			// 如果第一次空闲,则获取到要运行的IdleHandler的数量。
			// Idle处理,仅在队列为空或队列中的第一个消息(可能是一个屏障),将在将来被处理的情况下运行。
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                // 第一次空闲,并且队列为空或者当前时间未到头的执行时刻,获取IdleHandler数量。
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // 没有空闲handlers要运行。循环并等待更多。
                
      // 如果暂时没有 Idle Handler 需要处理,则进入下一次循环
            // 为使下次循环如果出现新的 Idle Handler 能有机会执行
            // 不重置计数器,仍为初始值 -1
                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;
    }
}
复制代码

小结

移除Message

说明:

  1. 一个MessageQueue对应多个Message,一个Message对应一个Handler,所以一个MessageQueue可能对应多个Handler(多个Handler共用一个Looper的情况)。
  2. 一个MessageQueue可能对应多个相同Message类型(Messagetargetwhatobj相同)或相同Callback类型(Messagetargetcallbackobj相同)的消息。

removeMessages()

移除Messages

void removeMessages(Handler h, int what, Object object) {
    if (h == null) {
	    // Handler为空,直接返回,因为得需要Handler区分是哪个Handler的消息。
        return;
    }
	
	// 加入同步锁,保证线程安全,因为Handler可能会在任意线程调用移除Message、Callback等方法。
    synchronized (this) {
		// 当前消息,默认为Head。
        Message p = mMessages;

        // 删除前面符合条件的所有Message(即队首是删除目标,从头开始删除,直到不符合为止)。
        while (p != null && p.target == h && p.what == what
               && (object == null || p.obj == object)) {
            // 当前消息不为空,并且handler、what和目标相同,并且不匹配object或者匹配和目标相同,则移除当前消息。
            Message n = p.next; // 下个消息
            mMessages = n; // 因为要移除当前的,所以Head为下一个。
            p.recycleUnchecked(); // 当前的消息回收
            p = n; // 当前的为下一个,以便循环。
        }

        // 删除前面删除后剩余部分符合条件的所有Message。
        while (p != null) {
            Message n = p.next; // 下个消息
            if (n != null) { // 有下个消息
                if (n.target == h && n.what == what
                    && (object == null || n.obj == object)) {
                    // 下个消息handler、what和目标相同,并且不匹配object或者匹配和目标相同,则移除下个消息。
                    Message nn = n.next; // 下下个消息
                    n.recycleUnchecked(); // 下个消息回收
                    p.next = nn; // 下个消息为下下个消息,进行移除下个消息。
                    continue; // 当前的消息位置不变,以便再次进行判断是否下一个符合。
                }
            }
            p = n; // 当前的为下个,以便循环寻找匹配上面if的。
        }
    }
}
复制代码

removeMessages(Handler, int, Object)方法,为删除MessageQueue所有与参数相同Message类型(Messagetargetwhatobj相同)的消息。

说明:

  1. 它会先删除前面符合条件的所有Message(即队首是删除目标,从头开始删除,直到不符合为止),后删除前面删除后剩余部分符合条件的所有Message
  2. 参数object为空,为不匹配Messageobj,否则匹配是否和object相同。
  3. HandlerremoveMessages()方法,调用的就是此方法
  4. Handler移除消息相关介绍,请看三方库-Handler源码解析-Handler-移除Messages、Callbacks

移除Callbacks

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;
        }
    }
}
复制代码

removeMessages(Handler, Runnable, Object)方法,为删除MessageQueue所有与参数相同Callback类型(Messagetargetcallbackobj相同)的消息。

说明:

  1. 它的删除过程removeMessages(Handler, int, Object)方法相同只是原来Messagewhat判断改为Messagecallback判断。
  2. HandlerremoveCallbacks()方法,调用的就是此方法
  3. Handler移除消息相关介绍,请看三方库-Handler源码解析-Handler-移除Messages、Callbacks

removeCallbacksAndMessages()

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;
        }
    }
}
复制代码

removeCallbacksAndMessages(Handler, Object)方法,为删除MessageQueue中此Handler发出所有MessageCallbackMessagetargetobj相同)。

说明:

  1. 它的删除过程removeMessages(Handler, int, Object)removeMessages(Handler, Runnable, Object)方法相同只是原来Messagewhat判断或callback判断去掉了。
  2. HandlerremoveCallbacksAndMessages()方法,调用的就是此方法
  3. 可以调用handler.removeCallbacksAndMessages(null)删除Handler所有MessagesCallbacks
  4. Handler移除消息相关介绍,请看三方库-Handler源码解析-Handler-移除Messages、Callbacks

小结

是否有Message

hasMessages()

是否有Message

boolean hasMessages(Handler h, int what, Object object) {
    if (h == null) {
	    // Handler为空,直接返回。
        return false;
    }
    
	// 加入同步锁,保证线程安全,因为Handler可能会在任意线程调用是否有Message、Callback等方法。
    synchronized (this) {
	    // 当前消息,默认为Head。
        Message p = mMessages;
        // 遍历判断是否有
        while (p != null) {
            if (p.target == h && p.what == what && (object == null || p.obj == object)) {
	            // 当前消息handler、what和目标相同,并且不匹配object或者匹配和目标相同,则返回true。
                return true;
            }
            p = p.next; // 当前的为下一个,以便循环。
        }
        return false; // 没找到,返回false。
    }
}
复制代码

hasMessages(Handler, int, Object)方法,为判断MessageQueue是否有与参数相同Message类型(Messagetargetwhatobj相同)的消息。

说明:

  1. 它会遍历MessageQueue中的所有Message只要有一条符合条件,就返回ture否则返回false
  2. 参数object为空,为不匹配Messageobj,否则匹配是否和object相同。
  3. HandlerhasMessages()方法,调用的就是此方法
  4. Handler是否有消息相关介绍,请看三方库-Handler源码解析-Handler-是否有Messages、Callbacks

是否有Callback

@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
boolean hasMessages(Handler h, Runnable r, Object object) {
    if (h == null) {
        return false;
    }

    synchronized (this) {
        Message p = mMessages;
        while (p != null) {
            if (p.target == h && p.callback == r && (object == null || p.obj == object)) {
                return true;
            }
            p = p.next;
        }
        return false;
    }
}
复制代码

hasMessages(Handler, Runnable, Object)方法,为判断MessageQueue是否有与参数相同Callback类型(Messagetargetcallbackobj相同)的消息。

说明:

  1. 它的判断过程hasMessages(Handler, int, Object)方法相同只是原来Messagewhat判断改为Messagecallback判断。
  2. HandlerhasCallbacks()方法,调用的就是此方法
  3. Handler是否有消息相关介绍,请看三方库-Handler源码解析-Handler-是否有Messages、Callbacks

是否有Messages或Callbacks

boolean hasMessages(Handler h) {
    if (h == null) {
        return false;
    }

    synchronized (this) {
        Message p = mMessages;
        while (p != null) {
            if (p.target == h) {
                return true;
            }
            p = p.next;
        }
        return false;
    }
}
复制代码

hasMessages(Handler)方法,为判断MessageQueue是否有Handler发出所有MessageCallbackMessagetarget相同)。

说明:

  1. 它的判断过程hasMessages(Handler, int, Object)hasMessages(Handler, Runnable, Object)方法相同只是原来Messagewhatobj判断或callbackobj判断去掉了。
  2. HandlerhasMessagesOrCallbacks()方法,调用的就是此方法
  3. Handler是否有消息相关介绍,请看三方库-Handler源码解析-Handler-是否有Messages、Callbacks

小结

退出MessageQueue

quit()

void quit(boolean safe) {
    if (!mQuitAllowed) {
	    // 不允许退出(只有MainLooper不允许退出),再退出,抛出异常(主线程不运行退出)。
        throw new IllegalStateException("Main thread not allowed to quit.");
    }

	// 加入同步锁,保证线程安全,因为Looper可能会在任意线程调用退出方法。
    synchronized (this) {
        if (mQuitting) {
	        // 已经退出中,再退出,不操作。
            return;
        }
        // 标记退出中
        mQuitting = true;

		// 判断是否是安全的退出
        if (safe) {
	        // 安全的,移除未来(当前时间点以后)的所有消息。
            removeAllFutureMessagesLocked();
        } else {
	        // 不安全的,移除所有消息。
            removeAllMessagesLocked();
        }

        // 唤醒,防止在阻塞中。
        nativeWake(mPtr);
    }
}
复制代码

quit()方法,为退出MessageQueue,会标记mQuittingtrue,参数safe是否安全退出安全退出会调用removeAllFutureMessagesLocked()方法,移除未来(当前时间点以后)的所有消息。不安全退出会调用removeAllMessagesLocked()方法,移除所有消息。

说明:

  1. 不允许退出MessageQueue退出后抛出异常
  2. Looperquit()quitSafely()方法,调用的就是此方法
  3. Looper退出相关介绍,请看三方库-Handler源码解析-Looper-退出Looper

我们先来看一下,不安全退出调用的removeAllMessagesLocked()方法。

removeAllMessagesLocked()

private void removeAllMessagesLocked() {
	// 当前消息,默认为Head。
    Message p = mMessages;
    // 遍历所有消息,然后进行回收。
    while (p != null) {
        Message n = p.next; // 下个消息
        p.recycleUnchecked(); // 回收当前消息
        p = n; // 当前为下个,以便循环。
    }
    // Head为空,断开和其它消息的链接,使队列为空。
    mMessages = null;
}
复制代码

removeAllMessagesLocked()方法,为移除MessageQueue所有消息

我们再来看一下,安全退出调用的removeAllFutureMessagesLocked()方法。

removeAllFutureMessagesLocked()

private void removeAllFutureMessagesLocked() {
	// 当前时间
    final long now = SystemClock.uptimeMillis();
    Message p = mMessages; // 当前消息,默认为Head。
    if (p != null) {
	    // 队列有数据,进行移除。
        if (p.when > now) {
	        // 队首的执行时刻大于现在的时间,说明之后的消息都是未来(以后)执行的,所以移除所有消息。
            removeAllMessagesLocked();
        } else {
	        // 非全部未来(以后)执行,找到位置,进行移除之后的。
            Message n; // 下个消息
            // 遍历,找到移除始发位置。
            for (;;) {
                n = p.next; // 下个消息
                if (n == null) {
	                // 没有下个消息,说明到队尾了,还未走下面if退出,说明所有消息都是以前的消息,直接返回。
                    return;
                }
                if (n.when > now) {
	                // 下个消息执行时刻大于当前时间,再加上队列里的时刻是从小到大有序的,
	                // 则说明当前时间,比当前消息执行时刻大,比下个消息执行时刻小,所以即找到位置,退出遍历。
                    break;
                }
                p = n; // 当前为下个,以便循环。
            }
            // 移除之后的
            p.next = null; // 断开后续链接,即已经移除成功。
		    // 遍历之后所有消息,然后进行回收。
            do {
                p = n;
                n = p.next;
                p.recycleUnchecked(); // 回收消息
            } while (n != null);
        }
    }
}
复制代码

removeAllFutureMessagesLocked()方法,为移除MessageQueue未来(当前时间点以后)的所有消息

小结

同步屏障

postSyncBarrier() @hide removeSyncBarrier() @hide

postSyncBarrier

postSyncBarrier()

public int postSyncBarrier() {
    return postSyncBarrier(SystemClock.uptimeMillis());
}
复制代码
private int postSyncBarrier(long when) {
    // 加入一个新的同步屏障token。
	// 我们不需要唤醒队列,因为屏障的目的是让它停滞。
    synchronized (this) {
        // 同步屏障消息可以有多个,用token区分,token通过mNextBarrierToken累加维护。
        final int token = mNextBarrierToken++;
        // 获取一个屏障消息(target为null)
        final Message msg = Message.obtain();
        msg.markInUse(); // 标记消息在用
        msg.when = when; // 记录执行时刻
        msg.arg1 = token; // 记录token

		// 根据when排序找到插入位置。
        Message prev = null; // 上个消息
        Message p = mMessages; // 当前消息,默认为Head。
        if (when != 0) {
            while (p != null && p.when <= when) {
	            // 当前不为空,并且当前时间小于目标时间,继续查找。
                prev = p; // 上个为当前
                p = p.next; // 当前为下个,以便循环。
            }
        }
        // 进行插入
        if (prev != null) {
	        // 进入了while循环,找到了位置,将消息在此位置插入。
            msg.next = p;
            prev.next = msg;
        } else {
	        // 未进入while循环,未找到了位置,将消息在队首插入。
	        // 未进入while循环,说明:队列为空,或队里的所有Message时刻都比屏障Message要晚。
            msg.next = p;
            mMessages = msg;
        }
        // 返回toke,为了移除用。
        return token;
    }
}
复制代码

removeSyncBarrier

removeSyncBarrier()

public void removeSyncBarrier(int token) {
    // 从队列中删除同步屏障token。
    // 如果队列不再被屏障阻碍,那么唤醒它。
    synchronized (this) {
        Message prev = null; // 上个消息
        Message p = mMessages; // 当前消息,默认为Head。
        // 遍历队列找到此token的屏障Message
        while (p != null && (p.target != null || p.arg1 != token)) {
    	    // 当前不为空,并且当前的不是屏障消息或者是屏障消息但是token不相等,继续查找。
            prev = p;
            p = p.next;
        }
        if (p == null) {
            // 队列为空,或到末尾了没找到,抛出异常(指定的消息队列同步屏障token尚未发布或已被删除)。
            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) {
	        // 进入了while循环,找到了位置,将消息在此位置移除。
            prev.next = p.next;
            needWake = false; // 不需要唤醒
        } else {
	        // 未进入while循环,未找到了位置,将消息在队首移除。
	        // 未进入while循环,说明:队列为空,或队首就是此屏障消息。
            mMessages = p.next;
            // 如果队列为空,或队首是屏障消息,则唤醒。
            needWake = mMessages == null || mMessages.target != null;
        }
        // 回收消息
        p.recycleUnchecked();

        // 判断是否应该唤醒,如果loop退出,那么它已经醒了。
        if (needWake && !mQuitting) {
	        // 唤醒
            nativeWake(mPtr);
        }
    }
}
复制代码

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.
     */
     // 当消息队列耗尽消息并将等待更多消息时调用。返回true以保持空闲处理程序处于活动状态,返回false以移除它。如果队列中仍有消息挂起,但它们都被调度到当前时间之后,则可以调用此函数。



    boolean queueIdle();
}
复制代码

addIdleHandler()

public void addIdleHandler(@NonNull IdleHandler handler) {
    if (handler == null) {
        throw new NullPointerException("Can't add a null IdleHandler");
    }
    synchronized (this) {
        mIdleHandlers.add(handler);
    }
}
复制代码

removeIdleHandler()

public void removeIdleHandler(@NonNull IdleHandler handler) {
    synchronized (this) {
        mIdleHandlers.remove(handler);
    }
}
复制代码

猜你喜欢

转载自juejin.im/post/7085977128092565512
今日推荐