使用共享ViewModel和SharedFlow实现Fragment间数据传输问题求助
问题原因排查
- 默认SharedFlow无重放缓存:
MutableSharedFlow默认构造参数replay = 0,只会把数据发射给发射时刻已经处于活跃状态的订阅者。你的执行顺序是Fragment A先调用sendData发射数据,之后才跳转创建Fragment B,等Fragment B订阅SharedFlow的时候,之前发射的"Hello"已经被丢弃,自然收不到。 - 变量名拼写错误:Fragment B中你声明的ViewModel变量名为
viewModelShared,但收集数据时写的是viewModelMain.sharedFlow,变量名不匹配也会导致无法拿到正确的Flow实例。 - 协程收集方式存在风险:
launchWhenCreated只会在生命周期达到CREATED状态时启动协程,但不会在生命周期低于该状态时自动取消收集,可能引发内存泄漏和无效收集。
解决方案
1. 给SharedFlow配置重放缓存
如果需要后续订阅的Fragment能收到之前发射的最新数据,给MutableSharedFlow设置replay = 1即可,修改ViewModel代码:
class SharedViewModel:ViewModel() { // 配置replay=1,缓存最近1条发射过的数据给新订阅者 private val _sharedFlow= MutableSharedFlow<String>(replay = 1) val sharedFlow= _sharedFlow.asSharedFlow() fun sendData(data:String){ viewModelScope.launch { _sharedFlow.emit(data) } } // 如果需要实现"单次事件、消费后就丢弃不重复接收"的需求,可新增这个方法,在Fragment B消费完数据后调用 fun clearReplayCache() { _sharedFlow.resetReplayCache() } }
2. 修正Fragment B的拼写错误和收集写法
注意使用repeatOnLifecycle需要项目依赖androidx.lifecycle:lifecycle-runtime-ktx:2.4.0及以上版本。
class FragmentB: Fragment() { private lateinit var viewModelShared: SharedViewModel //Others// override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModelShared = ViewModelProvider(requireActivity())[SharedViewModel::class.java] // 替换launchWhenCreated为更安全的repeatOnLifecycle,指定STARTED状态下才收集 lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { // 修正变量名拼写错误 viewModelShared.sharedFlow.collectLatest { data -> // 此处即可正常收到"Hello" // 如果是单次事件,消费完调用clearReplayCache避免下次页面重建重复收到 // viewModelShared.clearReplayCache() } } } } }
内容的提问来源于stack exchange,提问作者Matthew Nantes
相关产品推荐
相关产品推荐

