具有自定义数据源的分页库不会在房间更新时更新行
Paging Library with custom DataSource not updating row on Room update
我一直在实施新的 Paging Library with a RecyclerView with an app built on top of the Architecture Components。
填写列表的数据是从Room数据库中获取的。其实就是从网络上抓取,存储到本地数据库,提供给列表。
为了提供构建列表所需的数据,我实现了自己的自定义PageKeyedDataSource。除了一个小细节外,一切都按预期工作。显示列表后,如果列表的行元素的数据发生任何变化,则不会自动更新。因此,例如,如果我的列表显示的项目列表具有字段 name,突然,该字段在本地 Room 数据库中针对某个行项目进行了更新,该列表确实不会自动更新行 UI。
此行为仅在使用自定义数据源时发生,这与直接从 DAO, by returning a DataSource Factory 自动获取数据源不同。但是,我需要实现自定义数据源。
我知道它可以通过调用 DataSource 上的 invalidate() 方法来更新以重建更新后的列表。但是,如果应用程序一次显示 2 个列表(例如每个半屏),并且此项目出现在两个列表中,则需要为两个列表调用 invalidate()分开。
我想到了一个解决方案,而不是使用项目 class 的实例来填充它的每个 ViewHolder, it uses a LiveData 包装版本,让每一行自己观察变化项并在必要时更新该行 UI。尽管如此,我还是看到了这种方法的一些缺点:
- 一个LifeCycleOwner (such as the Fragment containing the RecyclerView for example) must be passed to the PagedListAdapter然后转发给ViewHolder,以便观察LiveData包裹的item。
- 将为每个列表的新行注册一个新的观察者,所以我根本不知道它是否具有过多的计算和内存成本,考虑到它会为应用程序中的每个列表完成,它有很多其中的列表。
- 例如,由于观察 LiveData 包装项目的 LifeCycleOwner 是包含 RecyclerView 的 Fragment,而不是 ViewHolder 本身,因此每当该项目发生更改时,观察者都会收到通知,即使包含的行该项目在那一刻甚至不可见,因为列表已经滚动,在我看来这是一种资源浪费,可能会不必要地增加计算成本。
我完全不知道,即使考虑到这些缺点,这是否是一种不错的方法,或者,也许,如果你们中有人知道任何其他更干净、更好的方法来管理它。
提前致谢。
自从上次检查这个问题以来已经有一段时间了,但是对于任何感兴趣的人,这是我的问题的原因 + library I made to observe LiveData properly from a ViewHolder(以避免必须使用问题中解释的解决方法)。
我的具体问题是由于错误使用 Kotlin 的 Data Classes。使用它们时,请务必注意(如文档中所述),toString()、equals()、hashCode() 和 copy() 将只考虑在 class' 构造函数中声明的所有那些属性,忽略那些在 class' body。一个简单的例子:
data class MyClass1(val prop: Int, val name: String) {}
data class MyClass2(val prop: Int) {
var name: String = ""
}
fun main() {
val a = MyClass1(1, "a")
val b = MyClass1(1, "b")
println(a == b) //False :) -> a.name != b.name
val c = MyClass2(2)
c.name = "c"
val d = MyClass2(2)
d.name = "d"
println(c == d) //True!! :O -> But c.name != d.name
}
这在实现 PagedListAdapter's DiffCallback, as if we are in a example's MyClass2 like scenario, no matter how many times we update the name field in our Room 数据库时特别重要,因为 DiffCallback 的 areContentsTheSame() 方法可能是总是 return true,使列表永远不会更新该更改。
如果上面解释的原因不是您问题的原因,或者您只是想能够从 ViewHolder[= 中正确观察 LiveData 实例38=],我开发了一个小型库,它为任何 ViewHolder 提供 Lifecycle,使其能够观察 LiveData 实例以正确的方式(而不是必须使用问题中解释的解决方法)。
我一直在实施新的 Paging Library with a RecyclerView with an app built on top of the Architecture Components。
填写列表的数据是从Room数据库中获取的。其实就是从网络上抓取,存储到本地数据库,提供给列表。
为了提供构建列表所需的数据,我实现了自己的自定义PageKeyedDataSource。除了一个小细节外,一切都按预期工作。显示列表后,如果列表的行元素的数据发生任何变化,则不会自动更新。因此,例如,如果我的列表显示的项目列表具有字段 name,突然,该字段在本地 Room 数据库中针对某个行项目进行了更新,该列表确实不会自动更新行 UI。
此行为仅在使用自定义数据源时发生,这与直接从 DAO, by returning a DataSource Factory 自动获取数据源不同。但是,我需要实现自定义数据源。
我知道它可以通过调用 DataSource 上的 invalidate() 方法来更新以重建更新后的列表。但是,如果应用程序一次显示 2 个列表(例如每个半屏),并且此项目出现在两个列表中,则需要为两个列表调用 invalidate()分开。
我想到了一个解决方案,而不是使用项目 class 的实例来填充它的每个 ViewHolder, it uses a LiveData 包装版本,让每一行自己观察变化项并在必要时更新该行 UI。尽管如此,我还是看到了这种方法的一些缺点:
- 一个LifeCycleOwner (such as the Fragment containing the RecyclerView for example) must be passed to the PagedListAdapter然后转发给ViewHolder,以便观察LiveData包裹的item。
- 将为每个列表的新行注册一个新的观察者,所以我根本不知道它是否具有过多的计算和内存成本,考虑到它会为应用程序中的每个列表完成,它有很多其中的列表。
- 例如,由于观察 LiveData 包装项目的 LifeCycleOwner 是包含 RecyclerView 的 Fragment,而不是 ViewHolder 本身,因此每当该项目发生更改时,观察者都会收到通知,即使包含的行该项目在那一刻甚至不可见,因为列表已经滚动,在我看来这是一种资源浪费,可能会不必要地增加计算成本。
我完全不知道,即使考虑到这些缺点,这是否是一种不错的方法,或者,也许,如果你们中有人知道任何其他更干净、更好的方法来管理它。
提前致谢。
自从上次检查这个问题以来已经有一段时间了,但是对于任何感兴趣的人,这是我的问题的原因 + library I made to observe LiveData properly from a ViewHolder(以避免必须使用问题中解释的解决方法)。
我的具体问题是由于错误使用 Kotlin 的 Data Classes。使用它们时,请务必注意(如文档中所述),toString()、equals()、hashCode() 和 copy() 将只考虑在 class' 构造函数中声明的所有那些属性,忽略那些在 class' body。一个简单的例子:
data class MyClass1(val prop: Int, val name: String) {}
data class MyClass2(val prop: Int) {
var name: String = ""
}
fun main() {
val a = MyClass1(1, "a")
val b = MyClass1(1, "b")
println(a == b) //False :) -> a.name != b.name
val c = MyClass2(2)
c.name = "c"
val d = MyClass2(2)
d.name = "d"
println(c == d) //True!! :O -> But c.name != d.name
}
这在实现 PagedListAdapter's DiffCallback, as if we are in a example's MyClass2 like scenario, no matter how many times we update the name field in our Room 数据库时特别重要,因为 DiffCallback 的 areContentsTheSame() 方法可能是总是 return true,使列表永远不会更新该更改。
如果上面解释的原因不是您问题的原因,或者您只是想能够从 ViewHolder[= 中正确观察 LiveData 实例38=],我开发了一个小型库,它为任何 ViewHolder 提供 Lifecycle,使其能够观察 LiveData 实例以正确的方式(而不是必须使用问题中解释的解决方法)。