简体   繁体   English

向后导航后,Android LiveData会观察到过时的数据

[英]Android LiveData observes stale data after navigating back

Question: 题:

How can I prevent my livedata immediately receiving stale data when navigating backwards? 向后导航时,如何防止livedata立即接收过时的数据? I am using the Event class outlined here which I thought would prevent this. 我正在使用此处概述的Event类,我认为这可以防止这种情况。

Problem: 问题:

I open the app with a login fragment, and navigate to a registration fragment when a live data email/password is set (and backend call says "this is a new account go register"). 我用一个登录片段打开该应用程序,并在设置了实时数据电子邮件/密码后导航到一个注册片段(后端调用显示“这是一个新帐户,请注册”)。 If the user hits the back button during the registration Android is popping back to login. 如果用户在注册过程中按下了“后退”按钮,则Android将弹出登录。 When the login fragment is recreated after a back press, it immediately fires the live data again with the stale backend response and I would like to prevent that. 当按下返回键后重新创建登录片段时,它将立即使用陈旧的后端响应再次触发实时数据,我想防止这种情况发生。

LoginFragment.kt LoginFragment.kt

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

private fun subscribeToLoginEvent() {
    //When a back press occurs, we subscribe again and this instantly 
    //fires with the same data it used to leave the screen 
    //(a Resource<User> with status=SUCCESS, data = null)

    viewModel.user.observe(viewLifecycleOwner, Observer { response ->
        Timber.i("login event observed....status:" + response?.status + ", data: " + response?.data)
        binding.userResource = response

        response?.let {
            val status = it.status
            val message = it.message

            if (status == Status.SUCCESS && it.data == null) {
                //This is a brand new user so we need to register now 
                navController()
                .navigate(LoginFragmentDirections.showUserRegistration()))
            }
            else if(status == Status.SUCCESS && it.data != null){
                goHome()
            }
        }
    })
}

LoginViewModel.kt LoginViewModel.kt

private val _loginCredentials: MutableLiveData<Event<Pair<String, String>>> = MutableLiveData()

val user: LiveData<Resource<User>> = Transformations.switchMap(_loginCredentials) {
    val data = it.getContentIfNotHandled()
    if(data != null && data.first.isNotBlank() && data.second.isNotBlank())
        interactor.callUserLoginRepo(data.first, data.second)
    else
        AbsentLiveData.create()
}

Okay there's two issues here which I hope helps somebody else. 好的,这里有两个问题,希望对其他人有所帮助。

  • The first is that the Event class does not appear to work with transformations. 首先是Event类似乎不适用于转换。 I think it is because the Event is literally pointing to the wrong live data ( _login_credentials vs user ) 我认为这是因为该事件实际上是指向错误的实时数据( _login_credentialsuser
  • The second problem is a little bit more fundamental but also blindingly obvious now. 第二个问题是更根本的问题,但现在也非常明显。 We are told all over the place that live data observations emit the latest data when a subscription is made to ensure you get the most up to date data. 订阅后,我们会被告知各地实时数据观测会发出最新数据,以确保您获得最新数据。 This means the way I am using live data here is simply incorrect, I can't subscribe to a login event, navigate somewhere, navigate back and re-subscribe because the ViewModel is rightfully giving me the latest data it has (because the login fragment was only detached, never destroyed). 这意味着我在这里使用实时数据的方式是完全错误的,我无法订阅登录事件,无法导航,无法导航并重新订阅,因为ViewModel正确地向我提供了它拥有的最新数据(因为登录片段只是超脱,从未被摧毁)。

Solution

The solution is to simply move the logic which performs the fetch one fragment deeper. 解决方案是简单地移动执行提取一个片段的逻辑的深度。 So instead of listening for user credentials + login click -> fetching a user -> and then navigating somewhere, I need to listen for user credentials + login click -> navigate somewhere -> and then start subscribing for my user live data. 因此,除了侦听用户凭据+登录单击->获取用户->然后导航至某个地方,我需要侦听用户凭据+登录单击->导航至某地方-> 然后开始订阅用户实时数据。 That way I can head back to the login screen as much as I want and not subscribe to some stale live data that was never destroyed. 这样,我可以尽可能多地返回登录屏幕,而不必订阅一些从未破坏的过时的实时数据。 And if I go back to login and then forwards the subscription and fragment were destroyed so I will appropriately be getting new data in that case. 如果我返回登录然后转发,则预订和片段被破坏,因此在这种情况下,我将适当地获取新数据。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM