【问题标题】:Fragment Back Navigation Blocked by ViewModelViewModel 阻止的片段返回导航
【发布时间】:2021-06-20 02:46:37
【问题描述】:

所以我正在尝试使用导航组件实现 mvvm 架构,这段代码片段工作得很好。问题是当我从 fragmentA 导航到 FragmentB 时,没有办法回到 FragmentA,就像按钮一样被阻止(如果我删除 ViewModel,导航可以正常工作,因此它与 ViewModel 有关)。

有人知道发生了什么吗?

private fun initVewModel() {
    myViewModel = MyViewModel()
    myViewModel = ViewModelProviders
        .of(this, createFor(myViewModel))
        .get(MyViewModel::class.java)
}

private fun setupObservers() {
    myViewModel.myData.observe(viewLifecycleOwner, Observer {
        it?.let { resource ->
            when (resource.status) {
                Status.SUCCESS -> {
                    resource.data?.let {
                        val action =
                            FragmentADirections.actionFragmentAToFragmentB()
                        Navigation.findNavController(requireView()).navigate(action)
                    }
                }
                Status.ERROR -> {
                    //TODO show an error
                    loading.visibility = View.GONE
                }
                Status.LOADING -> {
                    loading.visibility = View.VISIBLE
                }
            }
        }
    })

}

这是我的视图模型

class MyViewModel : ViewModel() {

    private val searchText = MutableLiveData<String>()

    //This method is called on a search button click
    fun setSearchText(text: String) {
        searchText.value = text
    }

    val myData = searchText.switchMap { text ->
        liveData(Dispatchers.IO) {
            emit(Resource.loading(data = null))
            try {
                emit(Resource.success(data = dataOrigin.getData(text)))
            } catch (exception: Exception) {
                exception.printStackTrace()
                emit(Resource.error(data = null, message = exception.message ?: "Error Occurred!"))
            }
        }
    }
}

【问题讨论】:

    标签: android kotlin mvvm android-jetpack android-mvvm


    【解决方案1】:

    那是因为你的myDataObserver会立即被返回导航的最新数据触发,并再次触发SUCCESS分支。

    我建议使用SharedFlows 或查看LiveDataSingleLiveEvent 模式,您只能使用一次事件。

    更新:

    消耗品模式的可能解决方案:

    class Consumable<T>(private val event: T) {
        private var isConsumed = false
    
        fun consume(): T? {
            if (isConsumed) return null
            isConsumed = true
            return event
        }
    
        fun peek() = event
    }
    

    然后在ViewModel中:

    val event = MutableLiveData<Consumable<YourEventClass>>()
    ...
    event.value = Consumable(XYEvent)
    

    你会像这样观察它:

    viewModel.event.observe{ event ->
        event.consume()?.let{
             // Do your navigation here
        }
    
    }
    

    此外,您可以为可消耗的 livedatas 编写扩展函数 .consume(),它会解开值

    【讨论】:

    • 我正在阅读有关 SingleLiveEvent 的文档,但我不太明白如何使其适应我的视图模型,如果问题不大,您能帮我多一点吗?
    猜你喜欢
    • 2019-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-08
    • 2020-06-03
    • 1970-01-01
    • 2016-07-13
    相关资源
    最近更新 更多