Android 更新房间整体性并遵守列表
想象一下,在主要活动中向您展示的帖子列表(如Facebook)。底层的“单一真相来源”是数据库,安卓的房间用来获取和观察这张帖子列表 这就是我观察数据的方式(由于许可证问题和简洁,细节被省略): 现在,每个帖子都有一个like按钮,以及单个帖子收到的like总数 现在,用户单击like按钮,您将发送一个操作。此操作可以执行以下操作: 1.1发出一个更新查询,增加帖子获得的喜欢次数 1.2标记数据库中的此特定帖子已被用户喜欢。Android 更新房间整体性并遵守列表,android,android-room,android-architecture-components,android-livedata,Android,Android Room,Android Architecture Components,Android Livedata,想象一下,在主要活动中向您展示的帖子列表(如Facebook)。底层的“单一真相来源”是数据库,安卓的房间用来获取和观察这张帖子列表 这就是我观察数据的方式(由于许可证问题和简洁,细节被省略): 现在,每个帖子都有一个like按钮,以及单个帖子收到的like总数 现在,用户单击like按钮,您将发送一个操作。此操作可以执行以下操作: 1.1发出一个更新查询,增加帖子获得的喜欢次数 1.2标记数据库中的此特定帖子已被用户喜欢。 实际上,向服务器发送一个POST请求,并更新那里的工件。(除其他外,此
@Query("UPDATE post SET liked= :liked, likes = likes + 1 WHERE id= :id")
void updateLike(int id, int liked);
(注意:这与不喜欢无关。它的效果类似于中等。一个用户可以给一篇文章N个喜欢。)
无论如何,当我发出该查询时,它会更新数据库。因为,我实际上是使用LiveData
观察这个数据库,所以我收到一个新的LiveData实体,然后将它连接到我的适配器上。我的适配器认为(数据集已更改),因此它更新了列表。执行此操作时,它还会滚动到列表中的第一篇文章。这就是问题所在
我怎样才能防止呢
一个可能的解决方案是检查传入列表和当前列表的post id是否相同,不要更新。但是,这意味着我不会从数据库中获得更新的No of likes
和其他内容。这反过来意味着,当用户单击like按钮时,我必须手动更改视图中like的编号
和like drawable的状态
这是正确的方法吗?或者,我可以做些什么,让我的数据库成为“唯一的真相来源”,同时仍然拥有类似的按钮功能
如果您使用的是RecyclerView.Adapter
,这意味着您有一个RecyclerView
或ViewPager2
,您可以使用它来解决您的问题
首先,不应在每次db发出新数据时重新创建适配器
当新数据可用时,您可以使用DiffUtil.calculateDiff(DiffUtil.Callback cb)
获取DiffUtil.DiffResult
对象,然后对结果调用dispatchUpdatesTo(适配器)
这样,新旧数据之间的所有更改都将单独应用。例如,假设您的旧列表是A、B、C
,如果新列表是A、X、B、C
,则只有X
将添加到RecyclerView(默认情况下,即使有动画)
下面是一个示例实现:
class ListDiffCalculator : DiffUtil.Callback() {
private var oldList = emptyList<MyModel>()
private var newList = emptyList<MyModel>()
fun computeDiff(oldList: List<MyModel>, newList: List<MyModel>): DiffUtil.DiffResult {
this.oldList = oldList
this.newList = newList
return DiffUtil.calculateDiff(this)
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
oldList[oldItemPosition].id == newList[newItemPosition].id
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
oldList[oldItemPosition].hashCode() == newList[newItemPosition].hashCode()
}
我实际上是在用LiveData观察这个数据库
你是如何观察数据库的
以及共享代码的。@AbdulKawee用代码片段更新了这个问题。谢谢你的回答,@lelloman。但是,我可以将DiffUtil与FragmentStatePagerAdapter+ViewPager一起使用吗?我不这么认为,我以为您使用的是回收器视图xD,但您可以。问题是RecyclerView.Adapter有方法通知特定的更改,而不仅仅是notifyDatasetChanged
。哦,太好了。但这仍然是在阿尔法和我永远不会得到批准使用它在生产中现在:P谢谢你的回答。对未来的读者来说真的很有帮助。是的,你现在不应该在生产中使用它:D,但是PagerAdapter没有API来通知个别的更改,所以你必须通过黑客破解它。对。酷,我想我会实现我在问题中提到的黑客。如果我们有机会转到RecyclerView或ViewPage2,我们将返回此答案:谢谢
class ListDiffCalculator : DiffUtil.Callback() {
private var oldList = emptyList<MyModel>()
private var newList = emptyList<MyModel>()
fun computeDiff(oldList: List<MyModel>, newList: List<MyModel>): DiffUtil.DiffResult {
this.oldList = oldList
this.newList = newList
return DiffUtil.calculateDiff(this)
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
oldList[oldItemPosition].id == newList[newItemPosition].id
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
oldList[oldItemPosition].hashCode() == newList[newItemPosition].hashCode()
}
class Adapter : RecyclerView.Adapter<ViewHolder>(), Observer<List<MyModel>> {
private var data = emptyList<MyData>()
override fun onChanged(newData: List<MyModel>?) {
newData?.let {
val diff = listDiffCalculator.computeDiff(data, newData)
this.data = newData
diff.dispatchUpdatesTo(this)
}
}
}
aViewModel.getAllPosts().observe(getActivity(), adapter)