MessageQueue:
- 一个用于存储Looper要dispatch的Message的底层容器, 不过其功能要远远超过这个注释的描述.
Message mMessages:
- 以链表的形式来保存Messge,这里的mMessages是当前队列的第一个要dispatch的Message,后面的通过Message本身的next来进行连接
interface IdleHandler:
- 其概念是一种连带处理,在当前的thread已经将自己应该执行的task(不包括没有到时的Task**)全部执行完,将要block的等待更多Message到来的时候**, 这个callback会被调用.
- 其函数queueIdle()return true则会保留这个IdleHandler,return false则会移除这个IdleHandler.
- addIdleHandler(IdleHandler handler)会将非null的hanlder加入到mIdleHandlers中(有同步,可见该函数的调用可能是多线程的)
- removeIdleHandler(IdleHandler handler)不解释.
构造函数: MessageQueue(boolean quitAllowed):
- 设置mQuitAllowed
- mPtr = nativeInit(): 在native层也要进行初始化,并且会返回native对象在native层的指针值.
dispose(): 只能在 messageQueue所属的looper所在的线程或者finalizer调用.
- nativeDestroy(mPtr);释放native层的资源
- mPtr = 0来防止重复dispose()
Message next(), 最重要的函数,Looper即是通过调用此函数来不断的从MessageQueue中取出Message进行处理:
- pendingIdleHandlerCount = -1,
- nextPollTimeoutMillis = 0
- native**Poll**Once(mPtr, nextPollTimeoutMillis), 调用此方法来同步阻塞的等待IO到来 + 超时参数, 读应的native方法是pollOnce(…) -> native层的Looper的pollOnce() -> pollInner(…) -> epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis), 可见最后是调用了高性能的epoll_wait(…)这种IO复用的调用, 任何对mEpollFd进行的IO操作都会使此方法结束阻塞等待并返回
- 因为addMessage这个操作是会被多线程调用的, 因此有关mMessages这个链表的操作需要同步.
- 获取当前时间 now.
- 如果当前的msg的target == null, 那么说明是一个barrier(而非一个真正的message, barrier也是一个特殊的message),这种情况下sync的message都被stall了,而async的则不受影响,沿着当前msg链表遍历知道找到一个Async的message为止, 当然,如果不是barrier, 那么直接取出当前mMessages就可以,就是这次要处理的message.
- 如果当前要处理的Message是null: 那么nextPollTimeoutMillis = -1
- 如果当前要处理的Message不是null:
- 如果now < msg.when, 说明还没有到处理这个msg的时间,还需要等待: nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE)
- 否则已经到了处理这个Msg的时机了, mBlocked = false; mBlocked代表的意思是表示是否next()会阻塞在等待pollOnce()这个函数的返回
- 下一步就是更新Message链表, 考虑msg是header和不是header的情况,包括了msg的next = null来将msg切断与message链表的联系。
- msg.markInUse()表明其当前正在被使用.
- 如果没有得到非null的要处理的Message(也没有pollOnce()继续等待), 那么会检查mQuitting,如果是,那么调用dispose(), 返回null, Looper.loop()在MessageQueue的next()返回null时也会结束自己的loop方法,从而整个HandlerThread结束(无限消息循环处理已经结束), 这里需要Quitting这个标志位的原因是不一定没有的到要处理的Message就一定要结束, 很可能之前已经把所有的Message已经全部处理完了
- 如果也没有quitting, 而也没有Message要处理的,那么就会考虑IdleHandler了,只有在当前MessageQueue是empty或者当前第一个Message的处理时间还没有到的情况下才会考虑。
- 如果也没有要做的IdleHandler,那么mBlocked = true, continue来继续阻塞等待将来的Message.
- 否则下一步会执行Idlehandler的操作, 一个细节是,因为IdleHandler本身的add/remove是有可能多线程调用的,但是如果在整个IdleHandler数组遍历回调的过程中都同步,会带来极大的性能损耗,因此这里会先将IdleHandler数组深拷贝(这样就算其他线程把这个数组改变了,也不会影响当前的Idle callback)一遍,然后不带同步的进行调用即可
- 遍历IdleJHandler的过程中,如果Idler的queueIdle()返回false,那么会将其从Idler数组中remove,可以看做一次one-shot的callback
- 在Idler都成功处理玩以后,会将nextPollTimeoutMillis = 0来将下次poll等待Message的超时设置为0即不等待,因为很有可能在处理Idler这段时间,其他线程已经post来了新的Message
quit(boolean safe):
- safe的含义不赘述了.
- 如果!mQuitAllowed, 那么直接抛异常,估计也只有Main thread是禁止quit的.
- 因为下面会操作mQuitting和Message链表,因此下面的操作需要进行同步,因为quit()可能在其他线程被调用.
- mQuitting = true; 显然这个标识位必须是true
- 如果safe->removeAllFutureMessagesLocked(), 否则removeAllMessagesLocked()
- 最后会调用nativeWake(mPtr)来唤醒next()方法(如果是通过nativePollOnce()在waiting的话, 如果不是waiting,也会因为之前已经将所有的Message remove以及不能再post Message的原因而最终走到next()中判断mQuitting的逻辑,从而next()返回null来结束loop())
enqueueSyncBarrier(long when):
- 其实就是插入一个target为null的Message, 复杂的逻辑在于要遍历当前的Message链表,将这个BarrierMessage插入到一个合适的位置,最后返回mNextBarrierToken++作为此Barrier的Token留待remove时用.
- 插入这个Message不需要进行wake nativePollOnce(), 因为本意就是使其中的Sync Message等待,不必多次一举
removeSyncBarrier(int token):
- 本质也是一个搜索+删除的链表操作.
- 不过remove barrer**可能需要wake当前等待的next(),因为barrier被拿掉了**
- 最后如果确认是需要wake的,并且当前也没有Quitting,那么会调用 nativeWake(mPtr).
nativeWake(mPtr):
- nativeWake(mPtr) -> MessageQueue.cpp的wake()->Looper.cpp的wake() -> write(mWakeWritePipeFd, “W”, 1); 向FD写入一个数据(“W”)来唤醒之前的epoll_wait()
enqueueMessage(Message msg, long when):
- 本质也是一个搜索+删除的链表操作.
- 会在这个过程中判断是否需要Wake, 如果需要,最后会调用nativeWake(mPtr).
各种形式的removeMessages(….)
- 搜索+删除的链表操作.
各种形式的hasMessages(…)
- 搜索链表的操作.
Android MessageQueue 源码笔记
最新推荐文章于 2024-07-12 23:12:58 发布