Android LiveData 在返回后观察到陈旧数据
Android LiveData observes stale data after navigating back
-
android
-
android-mvvm
-
android-livedata
-
android-architecture-components
-
android-architecture-navigation
问题:
如何防止我的实时数据在向后导航时立即接收到过时的数据?我正在使用 Event
class 概述 here 我认为可以防止这种情况发生。
问题:
我使用登录片段打开应用程序,并在设置实时数据 email/password 时导航到注册片段(后端调用显示 "this is a new account go register")。如果用户在注册过程中点击后退按钮,Android 会弹回登录。
当登录片段在按下后 重新创建 时,它会立即使用陈旧的后端响应再次触发实时数据,我想防止这种情况发生。
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
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()
}
好的,这里有两个问题,希望对其他人有所帮助。
- 首先是
Event
class 似乎不适用于转换。我认为这是因为事件实际上指向了错误的实时数据(_login_credentials
vs user
)
- 第二个问题有点更根本,但现在也很明显。我们到处都被告知,实时数据观察会在订阅时发出最新数据,以确保您获得最新数据。这意味着我在这里使用实时数据的方式完全不正确,我无法订阅登录事件、导航到某个地方、导航回来并重新订阅,因为 ViewModel 正确地给我它拥有的最新数据(因为登录片段只是分离,从未被摧毁)。
解决方案
解决方案是将执行获取一个片段的逻辑简单地移动到更深的位置。因此,我不需要监听用户凭据+登录单击 -> 获取用户 -> 然后导航到某处,而是需要监听用户凭据+登录单击 -> 导航某处 -> 然后 然后 开始订阅我的用户实时数据。这样我就可以随心所欲地返回登录屏幕,而不是订阅一些从未被破坏的陈旧实时数据。如果我返回登录然后转发订阅和片段被销毁,那么在这种情况下我将适当地获取新数据。
android
android-mvvm
android-livedata
android-architecture-components
android-architecture-navigation
问题:
如何防止我的实时数据在向后导航时立即接收到过时的数据?我正在使用 Event
class 概述 here 我认为可以防止这种情况发生。
问题:
我使用登录片段打开应用程序,并在设置实时数据 email/password 时导航到注册片段(后端调用显示 "this is a new account go register")。如果用户在注册过程中点击后退按钮,Android 会弹回登录。 当登录片段在按下后 重新创建 时,它会立即使用陈旧的后端响应再次触发实时数据,我想防止这种情况发生。
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
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()
}
好的,这里有两个问题,希望对其他人有所帮助。
- 首先是
Event
class 似乎不适用于转换。我认为这是因为事件实际上指向了错误的实时数据(_login_credentials
vsuser
) - 第二个问题有点更根本,但现在也很明显。我们到处都被告知,实时数据观察会在订阅时发出最新数据,以确保您获得最新数据。这意味着我在这里使用实时数据的方式完全不正确,我无法订阅登录事件、导航到某个地方、导航回来并重新订阅,因为 ViewModel 正确地给我它拥有的最新数据(因为登录片段只是分离,从未被摧毁)。
解决方案
解决方案是将执行获取一个片段的逻辑简单地移动到更深的位置。因此,我不需要监听用户凭据+登录单击 -> 获取用户 -> 然后导航到某处,而是需要监听用户凭据+登录单击 -> 导航某处 -> 然后 然后 开始订阅我的用户实时数据。这样我就可以随心所欲地返回登录屏幕,而不是订阅一些从未被破坏的陈旧实时数据。如果我返回登录然后转发订阅和片段被销毁,那么在这种情况下我将适当地获取新数据。