Navigation Components跳转至第二个Fragment后无法获取数据库数据
问题根源分析
- Repository的SharedFlow无重播配置:你在
shareIn中未指定replay参数,默认值为0。这意味着当第一个Fragment的订阅取消后,SharedFlow不会保留之前发射的数据;第二个Fragment订阅时,只有数据库发生新的变更才会收到数据,无法获取已存在的历史数据。 - ViewModel存在冗余协程:每次调用
getBaseCurrency()都会启动新的collect协程,若多次触发会导致重复发射状态,浪费资源且可能引发逻辑混乱。
修复方案
1. 修改Repository的SharedFlow配置
添加replay=1,让SharedFlow保留最近一次数据,确保新订阅者能立即获取已有数据:
val baseCurrency: Flow<BaseCurrencyModel> = currencyDAO.getBaseCurrency().shareIn( scope, SharingStarted.WhileSubscribed(5000L), replay = 1 // 保留最近一次发射的数据 )
2. 优化ViewModel实现
用stateIn直接转换Flow,替代手动collect到SharedFlow的逻辑,自动协程生命周期管理:
// 两个Fragment的ViewModel都可采用此写法 val baseCurrency: StateFlow<DatabaseState> = databaseRepository.baseCurrency .map { DatabaseState.Success(it.baseCurr) } .catch { emit(DatabaseState.Error(it.cause)) } .stateIn( viewModelScope, SharingStarted.WhileSubscribed(5000L), DatabaseState.Loading // 可选:添加加载初始状态 )
3. 简化Fragment的订阅逻辑
无需调用getBaseCurrency(),直接collect转换后的StateFlow:
// Fragment 1 viewLifecycleOwner.lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { mViewModel.baseCurrency.collect { baseCurrency -> when (baseCurrency) { is DatabaseState.Success<*> -> { mBinding.latestBase.text = String.format(getString(R.string.formatted_base_currency, baseCurrency.data)) } is DatabaseState.Error<*> -> { Log.i(TAG, "onCreateView: ERROR $baseCurrency") } is DatabaseState.Loading -> { // 可选:处理加载状态 } } } } } // Fragment 2 viewLifecycleOwner.lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { mViewModel.baseCurrency.collect { baseCurrency -> when (baseCurrency) { is DatabaseState.Success<*> -> { Log.i(TAG, "onCreateView: ${baseCurrency.data}") } is DatabaseState.Error<*> -> { Log.i(TAG, "onCreateView: ERROR $baseCurrency") } is DatabaseState.Loading -> { // 可选:处理加载状态 } } } } }
内容的提问来源于stack exchange,提问作者katowicenocom
相关产品推荐
相关产品推荐

