从第二个片段访问时 ViewModel 数据丢失状态

Posted

技术标签:

【中文标题】从第二个片段访问时 ViewModel 数据丢失状态【英文标题】:ViewModel Data Loses State When Accessed From Second Fragment 【发布时间】:2021-12-29 19:32:51 【问题描述】:

我的 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)
    

【问题讨论】:

每个 Fragment 都有自己的一组 ViewModel; FragmentA 的 ViewModel 在 FragmentB 中不可用。你read the documentation了吗? 当对多个 Fragment 使用相同的 ViewModel 时,您应该使用宿主 Activity 的上下文实例化每个 ViewModel。当然,这只有在所有相关片段都由相同的活动托管时才有效。 【参考方案1】:

您应该对两个片段都使用sharedViewModel。

在两个片段中使用这些代码行

private val viewModel: LoginViewModel by activityViewModels()

而不是

private val viewModel: LoginViewModel by viewModel()

【讨论】:

以上是关于从第二个片段访问时 ViewModel 数据丢失状态的主要内容,如果未能解决你的问题,请参考以下文章

无法更新 View Pager 中的中间片段。

如何在 Fragment 之间传递值

如何使用导航架构组件从片段中获取结果?

从第二个活动返回时,在 AsyncTask 调用后保存 RecyclerView 状态

从第二个警报视图按“确定”时,进度 hud 未显示

按下后如何将数据从第二个活动传递到第一个活动? - 安卓