携手创造,一起生长!这是我参加「日新计划 8 月更文应战」的第18天,点击查看活动详情

本篇文章将是介绍flow一些常见API系列的第五篇文章,希望能够协助大家更好的把握flow运用,熟练的应用于各种场景。

历史文章

这些flow常见API的运用,你必定需求把握!(一)
这些flow常见API的运用,你必定需求把握!(二)
这些flow常见API的运用,你必定需求把握!(三)
这些flow常见API的运用,你必定需求把握!(四)

stateIn()转变为暖流StateFlow

public fun <T> Flow<T>.stateIn(
    scope: CoroutineScope,
    started: SharingStarted,
    initialValue: T
): StateFlow<T> {
    val config = configureSharing(1)
    val state = MutableStateFlow(initialValue)
    val job = scope.launchSharing(config.context, config.upstream, state, started, initialValue)
    return ReadonlyStateFlow(state, job)
}
  • 冷流flow: 只有调用collect{}办法才会触发冷流履行

  • 暖流:暖流的履行不依赖是否增加调查者

stateIn()将冷流转换为暖流StateFlow(),这个流有几个特色:

  1. 需求给予一个初始值

  2. 是一个粘性流,类似于LiveData,会重放最终一个更新数据

  3. 过滤重复数据,也便是说,发送重复数据会进行丢弃

  4. 供给value特点获取内部的值

一般能够用作代替LiveData,直接运用暖流作为ViewModel中可调查的数据源,LiveData能完成的它都能完成,不能完成的它也都能完成。

stateIn()转变为暖流SharedFlow

public fun <T> Flow<T>.shareIn(
    scope: CoroutineScope,
    started: SharingStarted,
    replay: Int = 0
): SharedFlow<T> {
    val config = configureSharing(replay)
    val shared = MutableSharedFlow<T>(
        replay = replay,
        extraBufferCapacity = config.extraBufferCapacity,
        onBufferOverflow = config.onBufferOverflow
    )
    @Suppress("UNCHECKED_CAST")
    val job = scope.launchSharing(config.context, config.upstream, shared, started, NO_VALUE as T)
    return ReadonlySharedFlow(shared, job)
}

这个便是将冷流flow转换为SharedFlow,上面的暖流StateFlow完成了SharedFlow,它首要有以下几个特色:

  1. 无法经过.value的方式拜访内部值

  2. 经过replay参数自定义你需求的粘性或非粘性的暖流

两种冷流都需求传递一个SharingStarted类型的参数,这个参数有三种类型:EagerlyLazilyWhileSubscribed决定暖流的启动模式,这儿首要介绍WhileSubscribed

public fun WhileSubscribed(
    stopTimeoutMillis: Long = 0,
    replayExpirationMillis: Long = Long.MAX_VALUE
): SharingStarted =
    StartedWhileSubscribed(stopTimeoutMillis, replayExpirationMillis)
  • stopTimeoutMillis:这个参数指定一个在最终一个订阅者撤销和中止流履行的时刻距离,意思便是当最终一个个订阅者撤销后,隔stopTimeoutMillisms之后再中止流的履行。

  • replayExpirationMillis:这个参数指定一个再中止流履行和清除流缓存的时刻距离,也便是当中止流履行后,距离replayExpirationMillisms去清楚流的缓存。

举个应用场景,当应用反正屏切换时,订阅者就会被撤销,但是没必要去中止流履行或许整理缓存,由于反正屏往后很快就会重建从头显示,这样能更快的改写界面数据。

retryWhen{}

public fun <T> Flow<T>.retryWhen(predicate: suspend FlowCollector<T>.(cause: Throwable, attempt: Long) -> Boolean): Flow<T> =
    flow {
        var attempt = 0L
        var shallRetry: Boolean
        do {
            shallRetry = false
            val cause = catchImpl(this)
            if (cause != null) {
                if (predicate(cause, attempt)) {
                    shallRetry = true
                    attempt++
                } else {
                    throw cause
                }
            }
        } while (shallRetry)
    }

这个办法也很有用,出现异常时进行重试,并决定是否重试仍是弹出提示信息,比方当咱们进行网络恳求时,恳求失利就能够运用这个办法,一方面在retryWhen{}办法中记录错误信息并告诉下游流,一方面选择是否进行网络重试。

比方下面这个例子:

fun test2() {
    GlobalScope.launch {
        flow {
            emit("${10 / 随机数}")
        }
            .retryWhen { cause, attempt ->
                if (cause is ArithmeticException && attempt < 3) {
                    emit("retry")
                    true
                } else {
                    false
                }
            }.collect {
                println("jja: $it")
            }
    }
}

当上面的随机数出现0是就会触发ArithmeticException异常,这样retryWhen{}就能捕获并能够尝试重试,随机一个非0且能被整除的数,并且限制了重试次数为3次以为。

总结

关于flow常见api系列文章陆陆续续写了五篇了,暂时就告一段落,基本上常用的都介绍了一遍,希望能够给大家带来协助。