如何实现首个Flow发射后触发第二个Flow并随其变更实时更新?
问题描述
已实现API调用功能,希望允许用户选择排序顺序并将该选择保存至Datastore Preferences中。但由于排序选择与API数据均以Flow形式返回,无法实现让第二个Flow等待首个Flow发射数据,且在首个Flow发射新值时自动更新第二个Flow的逻辑。
示例代码
PreferencesRepository 相关
interface PreferencesRepository { fun getFilter(): Flow<OrderType> } class PreferencesRepositoryImpl @Inject constructor() : PreferencesRepository { override fun getFilter(): Flow<OrderType> = flow { delay(timeMillis = 300) // 模拟从datastore读取的初始延迟 emit(value = OrderType.ASCENDING) delay(timeMillis = 3000) // 模拟3秒后排序方式变更 emit(value = OrderType.DESCENDING) } }
ItemsRepository 相关
interface ItemsRepository { fun getItems(order: OrderType): Flow<List<ItemModel>> } class ItemsRepositoryImpl @Inject constructor() : ItemsRepository { private val dummyItems: List<ItemModel> = listOf( ItemModel(id = 1, title = "first item"), ItemModel(id = 2, title = "second item"), ItemModel(id = 3, title = "third item") ) override fun getItems(order: OrderType): Flow<List<ItemModel>> = flow { delay(timeMillis = 1000) // 模拟网络请求延迟 when (order) { OrderType.ASCENDING -> { emit(value = dummyItems) } OrderType.DESCENDING -> { emit(value = dummyItems.sortedByDescending { it.id }) } } } }
HomeViewModel 代码
@HiltViewModel class HomeViewModel @Inject constructor( private val itemsRepository: ItemsRepository, private val preferencesRepository: PreferencesRepository ) : ViewModel() { private val _filter = MutableLiveData<OrderType>() val filter: LiveData<OrderType> get() = _filter private val _items = MutableLiveData<List<ItemModel>>() val items: LiveData<List<ItemModel>> get() = _items init { // 我觉得这两个方法必须整合才能正常工作 getFilter() getItems() } private fun getFilter() = viewModelScope.launch { preferencesRepository.getFilter().collectLatest { orderType -> _filter.value = orderType println(orderType.name) } } private fun getItems() = viewModelScope.launch { itemsRepository.getItems( order = _filter.value ?: OrderType.ASCENDING // 无法如预期更新 ).collectLatest { items -> _items.value = items items.forEach { println(it.title) } } } }
当前Logcat输出

解决方案
核心问题在于当前getItems方法仅在初始化时获取一次过滤器值,后续过滤器更新不会触发新的API请求。可以通过Flow的flatMapLatest操作符关联两个Flow,实现过滤器更新时自动重新请求数据:
@HiltViewModel class HomeViewModel @Inject constructor( private val itemsRepository: ItemsRepository, private val preferencesRepository: PreferencesRepository ) : ViewModel() { // 将过滤器Flow转为StateFlow,替代LiveData更贴合Flow使用场景 private val filterFlow = preferencesRepository.getFilter() .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = OrderType.ASCENDING ) // 基于过滤器Flow自动触发数据请求 val items = filterFlow .flatMapLatest { orderType -> itemsRepository.getItems(orderType) } .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = emptyList() ) // 若仍需LiveData供View观察,可转换为LiveData val filter: LiveData<OrderType> = filterFlow.asLiveData() }
代码说明
stateIn:将冷Flow转为热StateFlow,支持多观察者共享数据,同时配置WhileSubscribed在View停止订阅时自动停止上游Flow,避免资源浪费。flatMapLatest:每当过滤器Flow发射新值时,会取消未完成的旧API请求,并立即发起新请求,确保数据始终匹配最新的排序规则。- 移除冗余的
MutableLiveData,通过Flow链式调用实现逻辑,代码更简洁且符合Jetpack架构最佳实践。
内容的提问来源于stack exchange,提问作者Denis
相关产品推荐
相关产品推荐

