StateFlow源码解析

472 阅读4分钟

flow的核心api:

1.声明一个stateFlow

2.更改stateFlow的值,setValue

3.调用collect函数,接收value的值

1.构建一个stateFlow对象

public fun <T> MutableStateFlow(value: T): MutableStateFlow<T> = StateFlowImpl(value ?: NULL)

这是一个函数,返回一个 StateFlowImpl (这个是对象),一定会有默认值 Null

2.setValue解析

private class StateFlowImpl<T>(
    initialState: Any // T | NULL
) : AbstractSharedFlow<StateFlowSlot>(), MutableStateFlow<T>, CancellableFlow<T>, FusibleFlow<T> {
    private val _state = atomic(initialState) // T | NULL
    private var sequence = 0 // serializes updates, value update is in process when sequence is odd

    @Suppress("UNCHECKED_CAST")
    public override var value: T
        get() = NULL.unbox(_state.value)
        set(value) { updateState(null, value ?: NULL) }

可以看到初始值,被atomic()函数包裹,这个是 “atomicfu”库的一个函数,需要单独添加依赖。

  1. updateState()

     private fun updateState(expectedState: Any?, newState: Any): Boolean {
         var curSequence = 0
         var curSlots: Array<StateFlowSlot?>? = this.slots // benign race, we will not use it
         synchronized(this) {
             val oldState = _state.value
             if (expectedState != null && oldState != expectedState) return false // CAS support
             if (oldState == newState) return true // Don't do anything if value is not changing, but CAS -> true
             _state.value = newState
             curSequence = sequence
             if (curSequence and 1 == 0) { // even sequence means quiescent state flow (no ongoing update)
                 curSequence++ // make it odd
                 sequence = curSequence
             } else {
                 // update is already in process, notify it, and return
                 sequence = curSequence + 2 // change sequence to notify, keep it odd
                 return true // updated
             }
             curSlots = slots // read current reference to collectors under lock
         }
         /*
            Fire value updates outside of the lock to avoid deadlocks with unconfined coroutines.
            Loop until we're done firing all the changes. This is a sort of simple flat combining that
            ensures sequential firing of concurrent updates and avoids the storm of collector resumes
            when updates happen concurrently from many threads.
          */
         while (true) {
             // Benign race on element read from array
             curSlots?.forEach {
                 it?.makePending()
             }
             // check if the value was updated again while we were updating the old one
             synchronized(this) {
                 if (sequence == curSequence) { // nothing changed, we are done
                     sequence = curSequence + 1 // make sequence even again
                     return true // done, updated
                 }
                 // reread everything for the next loop under the lock
                 curSequence = sequence
                 curSlots = slots
             }
         }
     }
    

flow对象中,将我们的值变成了一个成员变量,从这个意义上来讲,flow本身就是对变量的封装,就像User对name的封装一样。 更新完成数据之后,下面一个while(true)循环,将更新之后的对象 fire 出去,其他都是一些状态变量的判断。 (晦涩难懂,刚去看了一下suspendCoroutineUninterceptedOrReturn的概念)

4.makePending最终走到了 Continuation.resumeWith()方法。

public interface Continuation<in T> {
    /**
     * The context of the coroutine that corresponds to this continuation.
     */
    public val context: CoroutineContext

    /**
     * Resumes the execution of the corresponding coroutine passing a successful or failed [result] as the
     * return value of the last suspension point.
     */
    public fun resumeWith(result: Result<T>)
}

这个方法本质上是让协程 结束挂起状态。

  1. 上面理解有点不通,先看collect{}方法。

     override suspend fun collect(collector: FlowCollector<T>) {
         val slot = allocateSlot()
         try {
             if (collector is SubscribedFlowCollector) collector.onSubscription()
             val collectorJob = currentCoroutineContext()[Job]
             var oldState: Any? = null // previously emitted T!! | NULL (null -- nothing emitted yet)
             // The loop is arranged so that it starts delivering current value without waiting first
             while (true) {
                 // Here the coroutine could have waited for a while to be dispatched,
                 // so we use the most recent state here to ensure the best possible conflation of stale values
                 val newState = _state.value
                 // always check for cancellation
                 collectorJob?.ensureActive()
                 // Conflate value emissions using equality
                 if (oldState == null || oldState != newState) {
                     collector.emit(NULL.unbox(newState))
                     oldState = newState
                 }
                 // Note: if awaitPending is cancelled, then it bails out of this loop and calls freeSlot
                 if (!slot.takePending()) { // try fast-path without suspending first
                     slot.awaitPending() // only suspend for new values when needed
                 }
             }
         } finally {
             freeSlot(slot)
         }
     }
    

StateFlowSlot SharedFlowSlot

每一个collector都分配了一个flowSlot,用于记录collector的状态。 核心是这行:collector.emit(NULL.unbox(newState)) 我们最开始传入的函数就拿到了最新的值,然后执行方法。

所以从本质来看,抛去所有有的没的,flow的本质是这样的: 有一个值需要被观察,我们把这个值封装到一个对象中,然后观察者可以注册,当值变更的时候,通知观察者。 就是一个非常简单的观察者模式,但是结合了协程,以及各种状态维护,让整个源码看起来晦涩难懂。

但是如果只是一个观察者模式,也不知道大张旗鼓的封装如此多的东西,首先要解决观察者模式最大的问题。

线程问题,所以把collect设置为suspend函数,然后flow本身就可以切换线程做任务,同时不阻塞当前线程。

顺便过一下flow的核心点

flow("1").collect{print(it)}

flow("1") ----> 只是构建了一个对象,还没有执行任何函数。 调用collect()才真正开始执行,最终触发了

	private class SafeFlow<T>(private val block: suspend FlowCollector<T>.() -> Unit) : AbstractFlow<T>() {
	    override suspend fun collectSafely(collector: FlowCollector<T>) {
	        collector.block()
	    }
	}

public suspend inline fun <T> Flow<T>.collect(crossinline action: suspend (value: T) -> Unit): Unit =
    collect(object : FlowCollector<T> {
        override suspend fun emit(value: T) = action(value)
    })

这个block()即flow声明的那个函数,执行了emit()函数。

private fun emit(uCont: Continuation<Unit>, value: T): Any? {
    val currentContext = uCont.context
    currentContext.ensureActive()
    // This check is triggered once per flow on happy path.
    val previousContext = lastEmissionContext
    if (previousContext !== currentContext) {
        checkContext(currentContext, previousContext, value)
    }
    completion = uCont
    return emitFun(collector as FlowCollector<Any?>, value, this as Continuation<Unit>)
}

触发emitFun最后触发了 “action(value)”,这个 “action(value)”就是collect{}里面的函数。