Android Fragment从共享ViewModel收集SharedFlow问题。

3
目前我有一个 ViewPager2 Fragment(作为起始点),它包含两个子 Fragment:ActiveOrderFragmentCompletedOrderFragment,它们都有自己的 ViewModel 来处理 API 调用(获取活动订单和已完成订单)。
当用户点击订单项时,它将导航到 OrderEditorFragment,并且有一个“将项目设置为活动/已完成”按钮,点击该按钮将更新订单的状态(只是一个简单的 PUT 请求),然后返回到 ViewPager2 Fragment。
为了通知和刷新 ActiveOrderFragmentCompletedOrderFragment,我在 OrderViewModel 中创建了一个 SharedFlow,它是一个共享的 ViewModel
class OrderViewModel(application: Application) : AndroidViewModel(application) {
    private val uiScope = viewModelScope
    private val _isOrderStatusChanged = MutableSharedFlow<Boolean>(replay = 1)          

    val isOrderStatusChanged: SharedFlow<Boolean>
        get() = _isOrderStatusChanged

    fun updateIsOrderStatusChanged() = _isOrderStatusChanged.emit(uiScope, true)            
}

然后我在ActiveOrderFragmentCompletedOrderFragmentonCreateView()中观察(收集)这个SharedFlow
viewLifecycleOwner.lifecycleScope.launch {
    viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) {
        orderViewModel.isOrderStatusChanged.collect { 
            if (it) {
                Log.v("xxx", "refreshed!")
                viewModel.refreshActiveOrders()    //similar in CompletedOrderFragment
            }
        }
    }
}

问题来了:当我改变状态并返回页面时,它们都会收到通知并刷新。然而,现在我点击任何订单项目进入编辑页面但什么也不做,然后返回,collect{}再次被调用,这不是期望的行为。如何防止这种情况发生?我猜这与replay属性有关...
一些额外的信息:
  1. 为什么要使用 viewLifecycleOwner 而不是直接使用 lifecycleScope
  2. 为什么需要在 SharedFlow 中设置 replay = 1

在消费OrderStatusChanged事件后,您需要将isOrderStatusChanged重置为false。 - CTD
如果我真的需要进行“手动重置”,我会选择 StateFlow 而不是 SharedFlow,我选择 SharedFlow 是因为它被设计用于一次性事件。 - Sam Chen
如果你想触发它一次,改为 replay = 0 - Ticherhaz FreePalestine
@Ticherhaz 自由巴勒斯坦。这意味着你没有阅读我的最后一个链接,我必须将其设置为1。 - Sam Chen
你解决了这个问题吗? - MinYoung Lee
1个回答

0
MutableSharedFlow<Boolean>(replay = 1) == MutableStateFlow<Boolean>(false)

什么是回放意思

MutableSharedFlow<Boolean>(replay = 0) 不会捕获任何东西

MutableSharedFlow<Boolean>(replay = 1) 捕获最新的值

MutableSharedFlow<Boolean>(replay = 2) 捕获最新的两个值

orderViewModel.isOrderStatusChanged.collect {
            Log.i("isOrderStatusChanged","$it")
        }

如果你两次设置_isOrderStatusChanged的值不同,你会发现它的变化。

我已经提供了为什么需要将“replay”设置为1的原因,你可以查看最后一个链接。 - Sam Chen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接