在片段上单击“返回”时,观察者出现应用程序崩溃/导航问题

时间:2019-09-02 14:04:41

标签: android android-fragments android-architecture-components android-livedata

我有一个片段A,它向网络发送搜索查询,如果结果是肯定的,则使用Android导航组件导航到片段B,并使用观察者完成。

导航到片段B后,我单击屏幕顶部的“ <-”箭头,但没有导航回到片段A,而是再次重新加载了片段B。而且,如果使用设备上的本机“后退”按钮,则应用程序将崩溃,并显示“ illegalArgumentException导航目标未知”错误。

我检查了互联网上有关此问题的线索,但我所知道的是,发生这种情况是因为我在onViewCreated()中使用.observe,当我返回时,它再次被调用,并且因为livedata中已经有东西,它只是将我导航回B。

我尝试在onActivityCreated()中进行观察,并使用getViewLifeCycleOwner,但没有成功...唯一的帮助是在使用.observe之前,检查livedata是否具有观察者并返回true,但它似乎不正确。

这是viewModel:

private val getAssetResult = MutableLiveData<GeneralResponse<Asset>>()
private val updateAssetResult = MutableLiveData<GeneralResponse<Int>>()
private val deleteAssetResult = MutableLiveData<GeneralResponse<Int>>()

init {
    state.value = ViewState(false)
    Log.d(TAG, "State in init: $state")
}

fun getAssetResult(): LiveData<GeneralResponse<Asset>>{

    return getAssetResult
}

fun findAsset(req: GetAssetRequest) {

    scope.launch {
        setProgressIndicator(true)
        val result = repository.getAsset(req)

        getAssetResult.postValue(result)

        setProgressIndicator(false)
    }
}

这是片段:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    viewModel = ViewModelProvider(this).get(EditAssetViewModel::class.java)
    setupViewModel()
    initFields()
}


private fun setupViewModel() {

    if (viewModel.getAssetResult().hasObservers()) // <- This is the part that prevents the app from crashing.
        return

    viewModel.getAssetResult().observe(this, Observer {
        if (it == null) return@Observer

        handleSearchResult(it)
    })

    if (viewModel.getState().hasObservers())
        return

    viewModel.getState().observe(this, Observer { handleState(it) })
}

private fun handleSearchResult(response: GeneralResponse<Asset>) {

    if (response.singleValue == null) {
        Toast.makeText(context!!, response.errorMessage, Toast.LENGTH_SHORT).show()
        return
    }

    targetFragment?.let { it ->

        val bundle = bundleOf("asset" to response.singleValue)

        when(it) {
            "UpdateLocation" ->
                Navigation.findNavController(view!!).navigate(R.id.updateLocation, bundle)
            "EditAsset" -> {
                Navigation.findNavController(view!!).navigate(R.id.editAsset, bundle)
            }
        }
    }
}

如果我从setupViewModel函数中删除此部分:

如果(viewModel.getAssetResult()。hasObservers())         返回

使用设备按钮单击“后退”时,该应用程序将崩溃,或者返回到片段A,仅由于.observe功能而被导航回到片段B。

2 个答案:

答案 0 :(得分:0)

重写方法onBackPressed()以处理“ <-”箭头

答案 1 :(得分:0)

好像您用来发信号通知片段A的LiveData,它应该导航到片段B实际上是一个事件。事件仅发生一次,并且一旦消耗(导航事件完成)就消失了。因此,导航后,您需要向视图模型发送一条消息,说明导航已经进行,并且相应的数据持有者应再次为(例如)null。在片段A中,检查新值是否等于null,只有在这种情况下,才发出导航事件。这样可以防止片段A在后面的情况下立即再次切换到B。

如果您想了解有关使用实时数据进行活动的更多信息,请参阅此article