从第二个片段访问时 ViewModel 数据丢失状态
ViewModel Data Loses State When Accessed From Second Fragment
我用来保存用户登录数据的 ViewModel 出现问题。
我在用户登录后使用片段 A 中的用户数据更新此 ViewModel,但是当我尝试访问片段 B 中的数据时,我刚刚设置的数据字段始终为空。
初始化片段 B 时,最初从未观察到 user
LiveData 字段,但是,当我从片段 B 触发对 user
对象的更改时,会在片段 B 中正确观察到更改。看来我的 ViewModel 中字段的先前值永远不会到达片段 B,但新值可以。
为了完整性检查,我创建了一个简单的字符串变量(甚至不是 LiveData 对象),我将其设置为片段 A 中的一个值,然后,在导航到片段 B 之后,我打印了该值:它每次都未初始化。就好像我注入片段 B 的 ViewModel 与我注入片段 A 的 ViewModel 是完全分开的。
我错过了什么导致片段 B 中的 ViewModel 观察最初不触发片段 A 中设置的 user
的最后一个已知值?
片段A
class FragmentA : Fragment() {
private val viewModel: LoginViewModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.user.observe(this, {
it?.let {
//Called successfully every time
navigateToFragmentB()
}
})
val mockUserData = User()
viewModel.loginSuccess(mockUserData)
}
}
片段 B
class FragmentB : Fragment() {
private val viewModel: LoginViewModel by viewModel()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
...
viewModel.user.observe(viewLifecycleOwner, { user ->
user?.let {
binding.initialsBubble.text = user.getInitials()
} ?: navigateAway()
})
}
}
视图模型
class LoginViewModel(
private val loginRepo: LoginRepo
) : ViewModel() {
private val _user = MutableLiveData<User?>()
val user: LiveData<User?> = _user
fun loginSuccess(result: AuthenticationResult) {
val user = loginRepo.login(result)
_user.postValue(user)
}
}
两个片段都应该使用sharedViewModel。
在两个片段中使用这些代码行
private val viewModel: LoginViewModel by activityViewModels()
而不是
private val viewModel: LoginViewModel by viewModel()
我用来保存用户登录数据的 ViewModel 出现问题。
我在用户登录后使用片段 A 中的用户数据更新此 ViewModel,但是当我尝试访问片段 B 中的数据时,我刚刚设置的数据字段始终为空。
初始化片段 B 时,最初从未观察到 user
LiveData 字段,但是,当我从片段 B 触发对 user
对象的更改时,会在片段 B 中正确观察到更改。看来我的 ViewModel 中字段的先前值永远不会到达片段 B,但新值可以。
为了完整性检查,我创建了一个简单的字符串变量(甚至不是 LiveData 对象),我将其设置为片段 A 中的一个值,然后,在导航到片段 B 之后,我打印了该值:它每次都未初始化。就好像我注入片段 B 的 ViewModel 与我注入片段 A 的 ViewModel 是完全分开的。
我错过了什么导致片段 B 中的 ViewModel 观察最初不触发片段 A 中设置的 user
的最后一个已知值?
片段A
class FragmentA : Fragment() {
private val viewModel: LoginViewModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.user.observe(this, {
it?.let {
//Called successfully every time
navigateToFragmentB()
}
})
val mockUserData = User()
viewModel.loginSuccess(mockUserData)
}
}
片段 B
class FragmentB : Fragment() {
private val viewModel: LoginViewModel by viewModel()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
...
viewModel.user.observe(viewLifecycleOwner, { user ->
user?.let {
binding.initialsBubble.text = user.getInitials()
} ?: navigateAway()
})
}
}
视图模型
class LoginViewModel(
private val loginRepo: LoginRepo
) : ViewModel() {
private val _user = MutableLiveData<User?>()
val user: LiveData<User?> = _user
fun loginSuccess(result: AuthenticationResult) {
val user = loginRepo.login(result)
_user.postValue(user)
}
}
两个片段都应该使用sharedViewModel。
在两个片段中使用这些代码行
private val viewModel: LoginViewModel by activityViewModels()
而不是
private val viewModel: LoginViewModel by viewModel()