简体   繁体   English

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

[英]Application Crash/Navigation issue with observer when clicking “back” from fragment

I have a fragment A which sends a search query to the network, and if the result is positive uses Android navigation component to navigate to fragment B, and its done using observers. 我有一个片段A,该片段将搜索查询发送到网络,如果结果是肯定的,则使用Android导航组件导航到片段B,并使用观察者完成操作。

After navigation to fragment B, i click on "<-" arrow on the top of the screen, but instead of navigating back to fragment A it reloads fragment B again. 导航到片段B后,我单击屏幕顶部的“ <-”箭头,但没有导航回到片段A,而是再次重新加载了片段B。 And if using the native "back" button on the device, the app crashes with "illegalArgumentException navigation destination unknown" error. 并且,如果使用设备上的本机“后退”按钮,则应用程序将崩溃,并显示“ illegalArgumentException导航目标未知”错误。

I check the internet for clues on this issue, but all i learned is that this happens because i am using .observe in onViewCreated() and when i go back, it gets called again, and because livedata has something in it already, it just navigates me back to B. 我检查了互联网上有关此问题的线索,但是我所知道的是,发生这种情况是因为我在onViewCreated()中使用.observe,当我返回时,它又被调用了,并且因为livedata已经包含了某些东西,所以导航我回到B。

I have tried observing in onActivityCreated(), and using getViewLifeCycleOwner, but no success... the only thing that helped is checking if livedata has observers and returning if true, before using .observe, but it seems incorrect. 我尝试在onActivityCreated()中进行观察,并使用getViewLifeCycleOwner,但没有成功……唯一有用的方法是在使用.observe之前检查livedata是否具有观察者并返回true,但是似乎不正确。

This is the viewModel: 这是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)
    }
}

This is the fragment: 这是片段:

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)
            }
        }
    }
}

if i remove this part from the setupViewModel function: 如果我从setupViewModel函数中删除此部分:

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

the app will either crash when clicked "back" using the device button or go back to fragment A, just to be navigated back to fragment B because of the .observe function. 使用设备按钮单击“后退”时,该应用程序将崩溃,或者返回到片段A,仅由于.observe功能而被导航回到片段B。

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

Seems like the LiveData that you use to signal to fragment A that it should navigate to fragment B is actually an event. 似乎您用来发信号通知片段A的LiveData应该导航到片段B实际上是一个事件。 An event happens only once and once it is consumed (navigation event is done), it is gone. 事件仅发生一次,并且一旦消耗(导航事件完成)就消失了。 Therefore, after navigating you need to send a message to the viewmodel that the navigation took place and that the corresponding data holder should be (eg) null again. 因此,在导航之后,您需要向视图模型发送一条消息,该消息已发生导航,并且相应的数据持有者应再次(例如)为null。 In Fragment A you check that the new value is unequal to null, and only if this is the case, you issue the navigation event. 在片段A中,检查新值是否等于null,只有在这种情况下,才发出导航事件。 This would prevent fragment A to immediatelly switch to B again in the back scenario. 这样可以防止片段A在后面的情况下立即再次切换到B。

If you want to learn more about ways to use live data for events, please refer to this article . 如果您想了解更多有关使用实时数据进行事件的方法,请参阅本文

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 片段返回导航问题 - Fragment Back Navigation Issue 单击后退按钮时,Phonegap Android应用程序崩溃 - Phonegap Android Application Crash when clicking back button 导航历史记录为空时,Android中的“后退”按钮导致应用程序崩溃 - Back Button in Android Cause application to crash when navigation history is null 通过单击工具栏上的后退箭头,从子片段返回后,Hamburger Icon无法在父片段上打开导航抽屉 - Hamburger Icon not opening Navigation Drawer on parent fragment after returning from child fragment by clicking back arrow on toolbar 用户从片段返回时,结果不是应用程序吗? - Application not Result when user back from fragment? 从活动返回到片段时,OnBackPress应用程序崩溃 - OnBackPress App is crash when back From Activity to Fragment 按下后从片段转到主活动(导航视图) - When back pressed go to main Activity from fragment (Navigation view) 如何从 livedata 中删除观察者,使其在导航回片段时不会显示两次 - How to remove an observer from livedata so it doesn't show twice when navigating back to the fragment 当我从一个片段回到另一个片段时,我的观察者总是开火 - My observer is always firing when I come back from one fragment to another 如何在单击“主页”按钮时提供适当的反向导航以及片段 - how to provide proper back navigation with fragment on clicking the home button
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM