Android领域层:如何用单个UseCase整合本地与远程数据逻辑
整合Android领域层用例的解决方案
核心思路
要实现「仅返回一次本地数据Flow,后续仅触发远程更新」的需求,关键是把Flow提供和远程刷新操作分离:用例内部维护持续的本地数据Flow,单独提供触发远程同步的方法,避免每次刷新都生成新Flow。
方案1:封装为带刷新方法的用例类
将用例设计成类,内部初始化一次本地数据Flow,通过独立的refresh()方法触发远程获取与本地存储。
class GetReportUseCase( private val reportRepository: ReportRepository ) { // 仅初始化一次本地数据Flow,后续复用同一个实例 val reportFlow: Flow<Report> = reportRepository.getFromLocal() // 触发远程数据更新的挂起方法 suspend fun refresh() { // 拉取远程数据并存储到本地,本地Flow会自动感知数据变化并发射新值 val remoteReport = reportRepository.getFromRemote() reportRepository.saveToLocal(remoteReport) } }
ViewModel侧使用示例
class ReportViewModel( private val getReportUseCase: GetReportUseCase ) : ViewModel() { // 将冷Flow转为热StateFlow,确保配置变化时不重新收集 val reportState = getReportUseCase.reportFlow .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = Report.Empty ) // 用户触发刷新时调用 fun onRefresh() { viewModelScope.launch { getReportUseCase.refresh() } } }
UI只需收集reportState一次,每次调用onRefresh()时,用例会触发远程更新,本地数据变化后Flow自动通知UI刷新。
方案2:结合热Flow的invoke实现(可选)
如果坚持用operator invoke返回Flow,可将本地冷Flow转为热StateFlow,确保每次调用返回同一个实例:
class GetReportUseCase( private val reportRepository: ReportRepository, private val coroutineScope: CoroutineScope ) { private val _reportState = MutableStateFlow<Report>(Report.Empty) val reportState: StateFlow<Report> = _reportState.asStateFlow() init { // 初始化时订阅本地数据变化,自动更新StateFlow coroutineScope.launch { reportRepository.getFromLocal() .collect { _reportState.value = it } } } operator fun invoke(): StateFlow<Report> { return reportState } suspend fun refresh() { val remoteReport = reportRepository.getFromRemote() reportRepository.saveToLocal(remoteReport) // 本地数据更新后,上面的collect会自动同步到StateFlow } }
关键注意事项
- 确保
getFromLocal()返回的是冷Flow(比如Room的查询Flow),这样本地数据变化时会自动发射新值。 refresh()必须是挂起函数,避免在主线程执行远程请求等耗时操作。- ViewModel中使用
stateIn转换Flow,保证页面旋转等配置变化后,数据收集不会中断或重复初始化。
内容的提问来源于stack exchange,提问作者Sobhan
相关产品推荐
相关产品推荐

