更新Room实体并观察列表

问题描述 投票:3回答:1

想象一下在主要活动中呈现给您的帖子列表(如Facebook)。潜在的“单一事实来源”是数据库和Android的房间用于获取和观察这个帖子列表。

这就是我观察数据的方式(由于许可证问题和简洁而省略了详细信息):

faViewModel = ViewModelProviders.of(getActivity()).get(FAViewModel.class);

faViewModel.getAllPosts().observe(getActivity(),
    newPosts - > {

        if (newPosts != null && newPosts.size() > 0) {
            postsLoadingProgressBar.setVisibility(View.INVISIBLE);
        }

        //  if ((posts == null) || newPosts.get(0).getId() != posts.get(0).getId()) {
        // Update the cached copy of the posts in the adapter.
        posts = newPosts;
        mPostsAdapter = new PostsAdapter(this.getChildFragmentManager(), newPosts);
        mViewPager.setAdapter(mPostsAdapter);
        //                    }

    });

faViewModel.fetchNextData(currentPage);

现在,您还有一个附加到每个帖子的类似按钮,以及单个帖子收到的喜欢的总数。

现在,用户点击“赞”按钮,然后发送操作。此操作可以执行以下操作:

1.1发出更新查询,增加帖子获得的喜欢的数量。

1.2标记用户已喜欢数据库中的此特定帖子。

  1. 实际上向服务器发送POST请求并更新那里的工件。 (此用户喜欢的总喜欢和帖子等等。)

第2步是可行的,所以我们不要谈论它。但是,步骤1.1和1.2很棘手,因为当我发出更新查询时:

    @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和其他内容。这反过来意味着当用户点击类似按钮时,我将手动改变No of likes和Like drawable的状态在视图中。

这是正确的方法吗?或者有什么我可以做的仍然有我的数据库作为“单一的事实来源”,同时仍然有Like按钮工具。

任何其他想法/黑客都表示赞赏。

android android-room android-architecture-components android-livedata
1个回答
1
投票

你可以使用DiffUtil解决你的问题,如果你使用RecyclerView.Adapter,这意味着你有RecyclerViewViewPager2

首先,每次db发出新数据时都不应重新创建适配器。

当新数据可用时,您可以使用DiffUtil.calculateDiff(DiffUtil.Callback cb)获取DiffUtil.DiffResult对象,然后在结果上调用dispatchUpdatesTo(Adapter adapter)

这样,旧数据和新数据之间的所有更改都将单独应用。例如,假设您的旧列表是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()
}

您的适配器可以实现Observer<List<MyModel>>,以便您可以直接观察数据库,为简单起见省略其他适配器内容:

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)
© www.soinside.com 2019 - 2024. All rights reserved.