携手创作,共同成长!这是我参与「掘金日新计划 · 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()
,这个流有几个特点:
-
需要给予一个初始值
-
是一个粘性流,类似于
LiveData
,会重放最后一个更新数据 -
过滤重复数据,也就是说,发送重复数据会进行丢弃
-
提供
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
,它主要有以下几个特点:
-
无法通过
.value
的方式访问内部值 -
通过
replay
参数自定义你需要的粘性或非粘性的热流
两种冷流都需要传递一个SharingStarted
类型的参数,这个参数有三种类型:Eagerly
、Lazily
、WhileSubscribed
决定热流的启动模式,这里主要介绍WhileSubscribed
:
public fun WhileSubscribed(
stopTimeoutMillis: Long = 0,
replayExpirationMillis: Long = Long.MAX_VALUE
): SharingStarted =
StartedWhileSubscribed(stopTimeoutMillis, replayExpirationMillis)
-
stopTimeoutMillis
:这个参数指定一个在最后一个订阅者取消和停止流执行的时间间隔,意思就是当最后一个个订阅者取消后,隔stopTimeoutMillis
ms之后再停止流的执行。 -
replayExpirationMillis
:这个参数指定一个再停止流执行和清除流缓存的时间间隔,也就是当停止流执行后,间隔replayExpirationMillis
ms去清楚流的缓存。
举个应用场景,当应用横竖屏切换时,订阅者就会被取消,但是没必要去停止流执行或者清理缓存,因为横竖屏过后很快就会重建重新显示,这样能更快的刷新界面数据。
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系列文章陆陆续续写了五篇了,暂时就告一段落,基本上常用的都介绍了一遍,希望能够给大家带来帮助。