Android中使用SharedFlow时,后台返回重复显示相同值的解决方法
你当前使用了replay=1的SharedFlow,每次repeatOnLifecycle重新进入STARTED状态时,新订阅会收到SharedFlow重播的旧值(即初始化的100),导致Toast重复显示。要实现"值未变化时不显示Toast"的需求,可通过以下几种方式解决:
方案一:使用distinctUntilChanged过滤重复值
在收集流时添加distinctUntilChanged()操作符,自动过滤与前一次相同的值,仅当值真正变化时触发后续逻辑。
修改Activity代码:
lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { mainViewModel.a.distinctUntilChanged().collect { Toast.makeText(this@MainActivity, it.toString(), Toast.LENGTH_SHORT).show() } } }
该方案简单直接,无需修改ViewModel的流配置,同时能过滤所有重复发射的值(包括ViewModel中重复emit的相同值)。
方案二:调整SharedFlow的重播配置
若业务仅需接收新发射的值,无需保留旧值供新订阅重播,可将SharedFlow的replay设为0,同时设置extraBufferCapacity=1确保首次订阅能收到初始化的100:
修改ViewModel代码:
@HiltViewModel class MainViewModel @Inject constructor() : ViewModel() { private val _a = MutableSharedFlow<Int>(replay = 0, extraBufferCapacity = 1) val a = _a.asSharedFlow() init { viewModelScope.launch { _a.emit(100) } } }
配置后,只有ViewModel新发射值时,前台订阅才会收到数据;后台切回前台时无新发射,不会触发Toast显示。
方案三:在Activity中记录已处理的最后值
如需更精细控制,可在Activity中维护变量记录最后处理过的值,收集流时判断当前值是否与记录值相同,不同才显示Toast:
修改Activity代码:
private var lastHandledValue: Int? = null lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { mainViewModel.a.collect { if (it != lastHandledValue) { Toast.makeText(this@MainActivity, it.toString(), Toast.LENGTH_SHORT).show() lastHandledValue = it } } } }
注意:若需处理屏幕旋转等配置变化导致的Activity重建,需将lastHandledValue通过SavedStateHandle或ViewModel保存,避免重建后丢失记录。
内容的提问来源于stack exchange,提问作者Kang min gu
相关产品推荐
相关产品推荐

