【发布时间】:2021-10-24 17:28:49
【问题描述】:
在我的应用程序中,我使用 Room 库来处理用户数据,所有功能都已实现,如 developer.android.com 上的“Android Basics in Kotlin”教程单元 5。 在一个片段中,我需要从数据库中获取单个项目 - 为此我在片段的视图模型中实现了该功能:
fun retrievePlaceItem(id: Int): LiveData<PlaceItem> {
return itemDao.getPlaceItem(id).asLiveData()
}
ItemDao 从 Room Database 实例传递到 ViewModel Factory,该实例本身在自定义 Application 类中实例化。 这是 ItemDao 接口中使用的查询:
@Query("SELECT * FROM placeItem WHERE id = :id")
fun getPlaceItem(id: Int): Flow<PlaceItem>
ItemDao 中的数据以 Flow 形式返回,并在 fetching 函数中转化为 LiveData。 Fragment 本身通过传递的 id 观察函数的返回,当观察者触发时,该值存储在相应数据类型的 lateinit var 中。
lateinit var placeItem: PlaceItem
...
override fun onViewCreated(...) {
super.onViewCreated(view, savedInstanceState)
...
val id = navigationArgs.itemId
sharedViewModel.retrievePlaceItem(id)
.observe(this.viewLifecycleOwner) { selectedItem ->
placeItem = selectedItem
}
...
}
这工作完美无缺,项目被检索,观察者被触发,并初始化 lateinit var placeItem 以供进一步使用。
在稍后的另一个片段中,我使用具有完全相同功能的不同视图模型 - 我尝试以完全相同的方式检索值,观察片段的 onViewCreated 方法中的函数返回。代码完全相同,我尝试将其与教程中教授的内容进行比较 - 没有任何偏差。当我现在去使用该值时,我得到一个错误
kotlin.UninitializedPropertyAccessException:lateinit 属性 placeItem 尚未初始化
在使用日志检查我的代码后,我明白了以下内容:
- 调用了用于检索项目的视图模型函数
- 使用了正确的商品 ID
- 观察者大括号内的代码未执行
我尝试在两个片段中使用相同的视图模型,直到这两段代码之间没有更多可以想象的差异。但是第一个有效,第二个无效。我的代码中的某些内容在我使用数据库获取项目的两个实例之间产生了差异。
【问题讨论】:
-
在 `onViewCreated() 中未初始化的属性上使用
lateinit是不正确的,因为您不能保证它会尽早初始化。 LiveData 将在未来某个时间更新。这会使您的财产处于未初始化状态。通常,无论如何您都不需要将该值复制到某个本地属性。它表明代码中的其他地方存在设计错误。 -
@Tenfour04 感谢您的输入,我已经重写了我的代码以完全避免本地的 lateinit 属性,并且一切都按预期工作。看来我面前的障碍太大了,一开始我什至没有注意到明显的解决方案。
标签: android kotlin android-room observers