Kotlin 协程Flow、StateFlow、ShareFlow
数据流
数据流以协程为基础构建,可提供多个值。从概念上来讲,数据流是可通过异步方式进行计算处理的一组数据序列。所发出值的类型必须相同。例如,Flow<Int>
是发出整数值的数据流。
//在Acitivity中创建一个定时数据流并接收
lifecycleScope.launchWhenResumed {
flow {
while (true) {
emit(1)
delay(1000)
}
}.collect {
}
}
数据流包含三个实体:
- 提供方会生成添加到数据流中的数据。得益于协程,数据流还可以异步生成数据。
- 中介可以修改发送到数据流的值,或修正数据流本身。
- 使用方则使用数据流中的值。
- 流的启动:
//在作用域里launch
lifecycleScope.launchWhenResumed {
flow {
while (true) {
emit(1)
delay(1000)
}
}.collect {
}
}
//用 launchIn操作符
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) {//进度为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()//下载失败
}
//在Activity中接收
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
的可配置性极高的泛化数据流。
//通过 replay,您可以针对新订阅者重新发送多个之前已发出的值。
private val _stringFlow = MutableSharedFlow<String>(replay = 0)
val stringFlow: SharedFlow<String> = _stringFlow