如何在Fragment恢复时避免重复执行repeatOnLifecycle?

9
如何避免在返回到片段时再次执行collect()代码?

ViewModel 类

    private val _commitResult = MutableStateFlow<Map<String, Any>>(mapOf())
    val commitResult: StateFlow<Map<String, Any>> = _commitResult
Fragment code like this:

    viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED){
                viewModel.commitResult.collect { data ->
                    Logger.i("commitResult $data")
                    //navigate to another fragment
                }
            }
        }

当我先更改viewModel中的_commitResult值时,跳转到另一个fragment工作正常。不幸的是,当我返回到该fragment时,collect{ // navigate to another fragment}会再次执行。

我知道当返回到该fragment时,onCreateView会再次执行并且viewModel将在之前存储的数据之前发出,因此collect { // navigate to another fragment}会执行。我该如何避免这种情况?

与LiveData一样,我使用Event来解决这个问题。

open class Event<out T>(private val content: T) {

var hasBeenHandled = false
    private set // Allow external read but not write

/**
 * Returns the content and prevents its use again.
 */
fun getContentIfNotHandled(): T? {
    return if (hasBeenHandled) {
        null
    } else {
        hasBeenHandled = true
        content
    }
}

/**
 * Returns the content, even if it's already been handled.
 */
fun peekContent(): T = content
}

我该如何使用Stateflow来处理它呢?实际上,我不喜欢使用Event<.>来处理它,那我是不是用错了Stateflow的方式?我应该如何修复它呢?如果有人能帮忙,提前致谢。

这听起来像是一个典型的问题,但没有人回答它!!!然而,你可以通过使用replay = 0的SharedFlow来实现预期的结果。 - Yasin Hajilou
那对我没用 @YasinHajilou - osrl
1个回答

0

StateFlow 保留了它的状态,所以我建议你要么:

A)使用SharedFlowhttps://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-shared-flow/

B)使用一种模式来处理事件的解除。

class Vm: ViewModel() {
  
  private val mEvent = MutableStateFlow<MyResult?>(null)
  val event = mEvent.asStateFlow()

  fun dismissEvent() {
    mEvent.value = null
  }

}

class Frag: Fragment() {
  override fun onViewCreated() {
     vm.event.collect {
       navigate()
       vm.dismissEvent()
     }
  }
}

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