从没有中间转换变量的片段中观察 ViewModel LiveData

Posted

技术标签:

【中文标题】从没有中间转换变量的片段中观察 ViewModel LiveData【英文标题】:Observing ViewModel LiveData from fragments without intermediary transformation variable 【发布时间】:2021-08-23 12:41:25 【问题描述】:

我在我的 android 应用程序中遵循 MVVM 架构。 (https://developer.android.com/jetpack/guide)。我所有的存储库函数都返回一个 NetworkBoundResource 对象。您可以从 jetpack 指南链接阅读更多关于此设计实现的信息,或从 google here查看示例项目

在这个特定的问题中,当我在屏幕上下拉时,我试图通过网络重新获取信息。

当前的工作实施

片段监听器(屏幕下拉时触发)

binding.refresh.setOnRefreshListener 
    profileViewModel.refreshUserProfile()

然后在我的 ViewModel 中,我有一个 MutableLiveData 更新此函数调用的值

private val _refresh = MutableLiveData<Boolean>()

fun refreshUserProfile() 
    _refresh.value = true

_refresh.value发生变化时,会触发switchMap

val currentUserProfile: LiveData<Resource<UserProfile>> = _refresh.switchMap 
    if (it) 
        repository.getCurrentUserProfile(_username.value.toString())
     else 
        AbsentLiveData.create()
    

存储库函数


fun getCurrentUserProfile(username: String): LiveData<Resource<UserProfile>> 
    return object : NetworkBoundResource<UserProfile, UserProfile>(AppExecutors.getInstance()) 
        override fun saveCallResult(item: UserProfile) 
            userProfileDao.update(item)
        
        override fun shouldFetch(data: UserProfile?): Boolean 
            return true
        
        override fun loadFromDb(): LiveData<UserProfile> 
            return userProfileDao.load(username)
        
        override fun createCall(): LiveData<ApiResponse<UserProfile>> 
            return networkService.userProfileService.getUserProfileAsync(
                token,
                username
            )
        
    .asLiveData()

然后回到我的片段,我在这个 currentUserProfile ViewModel 变量上有一个观察者

profileViewModel.currentUserProfile.observe(viewLifecycleOwner,  userProfileResult ->
    when (userProfileResult.status) ...
)

我要做什么

我想跳过设置_refresh.value = true 的步骤。而是像这样直接观察存储库功能:

val currentUserProfile: LiveData<Resource<UserProfile>> = 
    repository.getCurrentUserProfile(_username.value.toString())

但是这个实现不会触发片段中的观察者。

问题 我不太明白为什么我不能用我的第二个实现来触发观察者。而且我也不确定我的初始实现是否是最佳或正确的。如果您熟悉此类设计,我将不胜感激。

【问题讨论】:

【参考方案1】:

我过去也遇到过类似的问题,而且大部分时间都与两件事有关:

    插入/更新的dao 实例与观察livedata 的dao 实例不同。 我的livedata 对象被包裹在其他一些实时数据中并返回。简而言之,它与 dao 返回的 livedata 实例不同。

您可以记录实例并检查它是否相同。它必须是单例的。如果您使用任何类型的依赖注入工具(例如 Dagger),请查看:https://***.com/a/44958478/9715339

我的猜测是,在你的情况下,它很可能是第二种情况。当您的livedata userProfileDao.load 被包裹在NetworkBoundResource.asLiveData() 中时,如果您查看NetworkBoundResource.result 的代码,它就是MediatorLiveData。 因此您不会主动收听userProfileDao 返回的相同实时数据。

只是为了确认这是问题您可以尝试收听从 userProfileDao.load(username) 返回的直接 livedata 。使用 & see 在您的存储库中创建一个方法。

您可以尝试更多地朝那个方向挖掘。

【讨论】:

我没有使用任何依赖注入工具。我确定房间数据库是单例的,但我不确定我的 DAO 是否是单例。从那以后,我将实现更改为使用 Flow 而不是 LiveData,并且我不再有观察数据的任何问题。所以我想排除 DAO 是问题所在。感谢您的回复。

以上是关于从没有中间转换变量的片段中观察 ViewModel LiveData的主要内容,如果未能解决你的问题,请参考以下文章

使用 LiveData 和 ViewModel 删除项目会导致重新发射

使用 ViewModel 和 LiveData 递增变量的简单片段示例 - 变量始终为空

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

永远观察实时数据的片段

Android Room LiveData观察器未更新

如何转换 ViewModel 以利用状态保存?