Kotlin 协程Flow、StateFlow、ShareFlow
数据流
数据流以协程为基础构建,可提供多个值。从概念上来讲,数据流是可通过异步方式进行计算处理的一组数据序列。所发出值的类型必须相同。例如,Flow<Int> 是发出整数值的数据流。
lifecycleScope.launchWhenResumed {
flow {
while (true) {
emit(1)
delay(1000)
}
}.collect {
}
}
数据流包含三个实体:
- 提供方会生成添加到数据流中的数据。得益于协程,数据流还可以异步生成数据。
- 中介可以修改发送到数据流的值,或修正数据流本身。
- 使用方则使用数据流中的值。
- 流的启动:
lifecycleScope.launchWhenResumed {
flow {
while (true) {
emit(1)
delay(1000)
}
}.collect {
}
}
flow {
while (true) {
emit(1)
delay(1000)
}
}.onEach{
}.launchIn(lifecycleScope)
- 流的异常捕获catch
flow {
while (true) {
emit(1)
delay(1000)
}
}.catch {
}.onEach {
}.launchIn(lifecycleScope)
- 流的开始与完成
flow {
while (true) {
emit(1)
delay(1000)
}
}.onStart {
}.catch {
}.onEach {
}.onCompletion {
}.launchIn(lifecycleScope)
StateFlow
StateFlow 是一个状态容器式可观察数据流,可以向其收集器发出当前状态更新和新状态更新。还可通过其 value 属性读取当前状态值。StateFlow 非常适合需要让可变状态保持可观察的类。与LiveData相似,比它强大,一般搭配协程使用。是热流:从此类数据流收集数据不会触发任何提供方代码。Flow一般是冷流,需要启动提供方发送数据。
比如下面的uiState就是一个状态流
class FileDownloadViewModel : ViewModel() {
private val _uiState = MutableStateFlow<FileState>(FileState.DownloadIdle)
val uiState: StateFlow<FileState> = _uiState
fun downloadFile() {
flow {
for (i in 1..100) {
_uiState.value = FileState.Downloading(i)
emit(i)
if (i == 100) {
_uiState.value = FileState.DownloadSuccess
}
}
}.flowOn(Dispatchers.IO)
.catch {
_uiState.value = FileState.DownLoadFail(RuntimeException("下载失败"))
}.onEach {
}.launchIn(viewModelScope)
}
}
sealed class FileState {
object DownloadIdle : FileState()
data class Downloading(val progress: Int) : FileState()
object DownloadSuccess : FileState()
data class DownLoadFail(val exception: Throwable) : FileState()
}
viewModel.uiState.onEach { state ->
when (state) {
is FileState.DownloadIdle -> {
}
is FileState.Downloading -> {
}
is FileState.DownloadSuccess -> {
}
is FileState.DownLoadFail -> {
}
}
}.launchIn(lifecycleScope)
StateFlow、Flow 和 LiveData
StateFlow 和 LiveData 具有相似之处。两者都是可观察的数据容器类,并且在应用架构中使用时,两者都遵循相似模式。不同:
StateFlow 需要将初始状态传递给构造函数,而 LiveData 不需要。- 当 View 进入
STOPPED 状态时,LiveData.observe() 会自动取消注册使用方,而从 StateFlow 或任何其他数据流收集数据的操作并不会自动停止。如需实现相同的行为,您需要从 Lifecycle.repeatOnLifecycle 块收集数据流。 - LiveData的监听需要传入LifecycleOwner,而StateFlow与Flow只需要传入相关的协程作用域即可。
SharedFlow
shareIn 函数会返回一个热数据流 SharedFlow ,比如一个Flow调用shareIn方法,会变成SharedFlow。此数据流会向从其中收集值的所有使用方发出数据。SharedFlow 是 StateFlow 的可配置性极高的泛化数据流。
private val _stringFlow = MutableSharedFlow<String>(replay = 0)
val stringFlow: SharedFlow<String> = _stringFlow
|