UI 上未观察到(可变)LiveData
(Mutable)LiveData is not getting observed on UI
我在 SO 上发布了很多类似的帖子,但我仍然找不到我无法在 UI 上观察到 LiveData
的原因。
我正在从事一个以学习为目的的项目。我想要做的是从我的 Room
数据库中获取一个值并将其显示在 UI 上。为了清楚起见,我只展示了相关的代码片段。
Dao.kt
@Query("SELECT maxValue FROM DoItAgainEntity WHERE id = :id")
fun getMaxValue(id: Int): LiveData<Int>
Repository.kt
override fun getMaxValue(activityId: Int) = doItAgainDao.getMaxValue(activityId)
ViewModel.kt
private val mMaxValue = MutableLiveData<Int>()
override fun getMaxValue(id: Int): LiveData<Int> =
Transformations.switchMap(mMaxValue) {
repository.getMaxValue(id)
}
Fragment.kt
viewModel.getMaxValue(activitiesAdapter.activities[position].id)
viewModel.getMaxValue(activitiesAdapter.activities[position].id).observe(viewLifecycleOwner, Observer {
// THIS CODE IS NEVER CALLED
Log.d("getMaxValueObserver",it.toString())
}
如何获得 LiveData
对象中提供的 Int
值?我知道,这几乎是一个新手问题,但你能解释一下我误解了什么吗?
非常感谢。
您没有更新 LiveData,因为您在 mMaxValue
上更新了 switchMap
。但是 LiveData 永远不会改变(正如我从您的示例中看到的那样)。
你其实不需要 属性 private val mMaxValue = MutableLiveData<Int>()
.
您可以将函数简化为:
fun getMaxValue(id: Int): LiveData<Int> = repository.getMaxValue(id)
开关地图
Returns a LiveData mapped from the input source LiveData by applying switchMapFunction to each value set on source.
在视图模型中
val mMaxValue = MutableLiveData<Int>()
override fun getMaxValue(id: Int){
repository.getMaxValue(id).observeForEver{it ->
mMaxValue.value = it
}
}
并且在 Activity 或片段中:
viewModel.getMaxValue(activitiesAdapter.activities[position].id)
viewModel.mMaxValue.observe(viewLifecycleOwner, Observer {
// THIS CODE IS NEVER CALLED
Log.d("getMaxValueObserver",it.toString())
}
要使此代码正常工作,需要执行几个步骤。非常感谢@ChristianB 解决了这个问题。这些是他的建议:
- 如果
Entity
有多个column/field,Room
返回LiveData<Int>
时如何知道你想要哪个值?因此,必须返回整行(定义为 Entity
对象),这将是 ID 与参数 :id
. 匹配的实体
Dao.kt
@Query("SELECT * FROM DoItAgainEntity WHERE id = :id")
fun getMaxValue(id: Int): LiveData<DoItAgainEntity>
- 在
Repository
中,您可以 filter/map 为您实际需要的任何字段。或者甚至将它映射到一个完全不同的(域)对象。
Repository.kt
override fun getMaxValue(activityId: Int): LiveData<Int> = doItAgainDao.getMaxValue(activityId).map { entity -> entity.maxValue }
switchMap(someLiveData)
仅在 someLiveData
的值更改时调用,然后可以从中返回另一个 liveData
。但这不是我的情况。我只是想从 LiveData
中获取一个值,该值归结为我的 DAO
。所以这里不需要switchMap
。
ViewModel.kt
override fun getMaxValue(id: Int) = repository.getMaxValue(id)
- 最后,观察
LiveData
对UI的作品。还应删除原始问题中对 viewModel.getMaxValue(activitiesAdapter.activities[position].id)
的重复调用。
Fragment.kt
viewModel.getMaxValue.observe(viewLifecycleOwner, Observer {
// THIS CODE HAS NOW BEEN CALLED :)
Log.d("getMaxValueObserver",it.toString())
return@Observer
})
- 最后但同样重要的是,如果
Entity
像我的情况一样更新,首先创建数据库后,完全卸载应用程序,适当增加数据库版本,所以Room
可以运行 对数据库进行迁移!清理并重建项目,使缓存无效/重新启动。
我在 SO 上发布了很多类似的帖子,但我仍然找不到我无法在 UI 上观察到 LiveData
的原因。
我正在从事一个以学习为目的的项目。我想要做的是从我的 Room
数据库中获取一个值并将其显示在 UI 上。为了清楚起见,我只展示了相关的代码片段。
Dao.kt
@Query("SELECT maxValue FROM DoItAgainEntity WHERE id = :id")
fun getMaxValue(id: Int): LiveData<Int>
Repository.kt
override fun getMaxValue(activityId: Int) = doItAgainDao.getMaxValue(activityId)
ViewModel.kt
private val mMaxValue = MutableLiveData<Int>()
override fun getMaxValue(id: Int): LiveData<Int> =
Transformations.switchMap(mMaxValue) {
repository.getMaxValue(id)
}
Fragment.kt
viewModel.getMaxValue(activitiesAdapter.activities[position].id)
viewModel.getMaxValue(activitiesAdapter.activities[position].id).observe(viewLifecycleOwner, Observer {
// THIS CODE IS NEVER CALLED
Log.d("getMaxValueObserver",it.toString())
}
如何获得 LiveData
对象中提供的 Int
值?我知道,这几乎是一个新手问题,但你能解释一下我误解了什么吗?
非常感谢。
您没有更新 LiveData,因为您在 mMaxValue
上更新了 switchMap
。但是 LiveData 永远不会改变(正如我从您的示例中看到的那样)。
你其实不需要 属性 private val mMaxValue = MutableLiveData<Int>()
.
您可以将函数简化为:
fun getMaxValue(id: Int): LiveData<Int> = repository.getMaxValue(id)
开关地图
Returns a LiveData mapped from the input source LiveData by applying switchMapFunction to each value set on source.
在视图模型中
val mMaxValue = MutableLiveData<Int>()
override fun getMaxValue(id: Int){
repository.getMaxValue(id).observeForEver{it ->
mMaxValue.value = it
}
}
并且在 Activity 或片段中:
viewModel.getMaxValue(activitiesAdapter.activities[position].id)
viewModel.mMaxValue.observe(viewLifecycleOwner, Observer {
// THIS CODE IS NEVER CALLED
Log.d("getMaxValueObserver",it.toString())
}
要使此代码正常工作,需要执行几个步骤。非常感谢@ChristianB 解决了这个问题。这些是他的建议:
- 如果
Entity
有多个column/field,Room
返回LiveData<Int>
时如何知道你想要哪个值?因此,必须返回整行(定义为Entity
对象),这将是 ID 与参数:id
. 匹配的实体
Dao.kt
@Query("SELECT * FROM DoItAgainEntity WHERE id = :id")
fun getMaxValue(id: Int): LiveData<DoItAgainEntity>
- 在
Repository
中,您可以 filter/map 为您实际需要的任何字段。或者甚至将它映射到一个完全不同的(域)对象。
Repository.kt
override fun getMaxValue(activityId: Int): LiveData<Int> = doItAgainDao.getMaxValue(activityId).map { entity -> entity.maxValue }
switchMap(someLiveData)
仅在someLiveData
的值更改时调用,然后可以从中返回另一个liveData
。但这不是我的情况。我只是想从LiveData
中获取一个值,该值归结为我的DAO
。所以这里不需要switchMap
。
ViewModel.kt
override fun getMaxValue(id: Int) = repository.getMaxValue(id)
- 最后,观察
LiveData
对UI的作品。还应删除原始问题中对viewModel.getMaxValue(activitiesAdapter.activities[position].id)
的重复调用。
Fragment.kt
viewModel.getMaxValue.observe(viewLifecycleOwner, Observer {
// THIS CODE HAS NOW BEEN CALLED :)
Log.d("getMaxValueObserver",it.toString())
return@Observer
})
- 最后但同样重要的是,如果
Entity
像我的情况一样更新,首先创建数据库后,完全卸载应用程序,适当增加数据库版本,所以Room
可以运行 对数据库进行迁移!清理并重建项目,使缓存无效/重新启动。