Kotlin 协程Flow、StateFlow、ShareFlow
数据流
数据流以协程为基础构建,可提供多个值。从概念上来讲,数据流是可通过异步方式进行计算处理的一组数据序列。所发出值的类型必须相同。例如,Flow<Int> 是发出整数值的数据流。
 //在Acitivity中创建一个定时数据流并接收
 lifecycleScope.launchWhenResumed {
            flow {
                while (true) {
                    emit(1)
                    delay(1000)
                }
            }.collect {
                
            }
        }
数据流包含三个实体:
- 提供方会生成添加到数据流中的数据。得益于协程,数据流还可以异步生成数据。
- 中介可以修改发送到数据流的值,或修正数据流本身。
- 使用方则使用数据流中的值。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jkY0fo00-1650466677712)(%E5%8D%8F%E7%A8%8B%E6%B5%81.assets/flow-entities.png)]
- 流的启动:
 //在作用域里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
/通过 replay,您可以针对新订阅者重新发送多个之前已发出的值。
 private val _stringFlow = MutableSharedFlow(replay = 0)
 val stringFlow: SharedFlow = _stringFlow










