【问题标题】:How to delete/remove PagedListAdapter item如何删除/移除 PagedListAdapter 项目
【发布时间】:2018-01-09 17:12:13
【问题描述】:

目前我正在使用 Android 架构组件 进行应用程序开发,一切都与分页库一起工作现在我想使用 PagedListAdapter 删除 recyclerview 项来填充我们需要添加数据源和从数据源列表正在使用 LiveData 更新不,我想从列表中删除一个项目 notifyItemRemoved() 正在从 PagedList 工作我收到此异常:

java.lang.UnsupportedOperationException


java.util.AbstractList.remove(AbstractList.java:638)

【问题讨论】:

标签: android android-recyclerview android-architecture-components


【解决方案1】:

由于您无法直接修改 PagedList 中的数据,因为我相信它是不可变的,因此在这种情况下实施删除项目的关键是在您的某处维护一个 支持数据集代表您迄今为止收到的所有数据的代码。 ArrayList 为我工作。

当您想要移除某个项目时,请将其从您的支持数据集中移除并在您的数据源上调用 invalidate。这将触发loadInitial() 调用,您可以在其中将支持数据集传递给callback.onResult() 函数。您的PagedListAdapter 将使用您提供的DiffUtil.ItemCallback 智能地确定其数据已更新,并将相应地更新自身。

本教程帮助我了解了在使用分页库时正确删除项目的正确流程: https://medium.com/@FizzyInTheHall/implementing-swipe-to-delete-with-android-architecture-components-a95165b6c9bd

与教程相关的 repo 可以在这里找到: https://gitlab.com/adrianhall/notes-app

【讨论】:

  • 这个解决方案似乎重新加载整个 RecyclerView,而不是 @cleanOK 提出的第二个解决方案。
  • 所以当 loadInitial() 调用被触发时,你需要将 backing 数据集传递给回调,并且已经设置好的 DiffUtil 逻辑将计算 RecyclerView 的适配器中的差异和新传入的数据。我不相信它会触发完全重新加载,因为 DiffUtil 的目的是避免这种情况 - PagedListAdapter 将使用它来帮助计算后台线程上的细粒度更新。如果可以的话,我绝对会推荐将 Room 与分页库一起使用——但对于不能的情况,我认为这是一个不错的选择。
  • 感谢@Tyler Bennett。我遇到的当前问题是 Firestore 查询通过自定义数据源连接到 PagedAdapter。但是,当我更新 Firestore 集合时,它不会更新 PagedList。相反,我需要使整个 DataSource 无效以反映 PagedList 中的更改。我会将 Room 连接到 PagedList 以查看是否允许实时更新 UI。
  • 这样做的问题是当数据源失效时,DiffUtil 必须检查所有项目。它不是最优的。仅删除 1 项,DiffUtil 有回调仅处理 1 项。
【解决方案2】:

我有同样的问题。 我的 PagedList 显示了 DataSource 工厂从服务器获取的项目。我想出了两个解决方案如何从列表中删除项目。

  1. 重新加载整个列表。 进行 API 调用以从服务器中删除项目,然后调用 pagedList.dataSource.invalidate()。 该解决方案的缺点是整个列表被清除,然后从服务器接收到所有项目。不是我想要的。
  2. 将结果存储在房间中。然后 PagedList 将直接从 Room 获取项目,而 PagedListAdapter 将自行管理删除/添加项目。

在 DAO 对象中

("SELECT * FROM YourModel")
fun getAll(): DataSource.Factory<Int, YourModel>
@Delete
fun delete(item: YourModel)

为了在用户滚动列表时更新数据库,我实现了 BoundaryCallback。当数据库中没有要显示的项目时调用它,它可以在同一页面的末尾调用,所以我确保不会多次执行相同的请求(在我的情况下,列表的键是页码)。

class YourModelBoundaryCallback(private val repository: Repository) : PagedList.BoundaryCallback<YourModel>() {
    private val requestArray = SparseArray<Disposable>()
    private var nextPage = 1
    private var lastPage = 1

    override fun onZeroItemsLoaded() {
        if (requestArray.get(1) == null) {
            requestArray.put(1, repository.getFirstPage()
                    .subscribe({
                        lastPage = it.total / PAGE_SIZE + if (it.total % PAGE_SIZE == 0) 0 else 1
                        nextPage++
                    }))

        }
    }

    override fun onItemAtEndLoaded(itemAtEnd: YourModel) {
        if (nextPage > lastPage) {
            return
        }
        if (requestArray.get(nextPage) == null) {
            requestArray.put(nextPage, repository.getNextPage(nextPage)
                    .subscribe({
                        lastPage = it.total / PAGE_SIZE + if (it.total % PAGE_SIZE == 0) 0 else 1
                        nextPage++
                    }))
        }
    }

    override fun onItemAtFrontLoaded(itemAtFront: YourModel) {
        // ignored, since we only ever append to what's in the DB
    }
}

PagedList 实例变成了这个

private val pagedListConfig = PagedList.Config.Builder()
        .setEnablePlaceholders(false)
        .setPrefetchDistance(3)
        .setPageSize(PAGE_SIZE)
        .build()

val pagedList = LivePagedListBuilder(yourModelDao.getAll(), pagedListConfig)
        .setBoundaryCallback(YourModelBoundaryCallback(repository))
        .build()

最后要从适配器中删除项目,我只需调用yourModelDao.remove(yourModel)

【讨论】:

  • 使用 Room 是只更新 UI 中被移除的项目还是整个 RecyclerView?目前使用我的 Firestore 自定义 DataSource 实现,当我使数据无效时,它会更新整个 RecyclerView,而不仅仅是所需的一项。如果 Room 解决了这个问题,我肯定会将 Room 连接到 Firestore。
  • 在重新阅读Consider How Content Updates Work 下的文档后,似乎唯一的实时更新方法是通过 PagedList 实现 Room:如果您直接从 Room 数据库更新加载数据自动推送到您应用的 UI。
  • @AdamHurwitz 正确,据我所知,只有 Room 实现会更新单个项目(或项目范围)而不是一次更新所有项目
  • 如何禁用从 Room 到 PagedListAdapter 的实时 UI 更新? 我已经构建了一个内容提要,其中项目的位置是根据从生成的 qualityScore 确定的用户交互。当基础数据发生变化时,Feed 的 UI 会实时更新并滑动刷新。我想配置禁用实时 UI 更新的选项,这样提要就不会不断变化。
  • @AdamHurwitz 最简单的想法是 1. 将 qualityScore 存储在另一个数据库实体中 2. 配置您的 DAO 对象以根据一些布尔标志访问该 qualityScore 实体
【解决方案3】:

通过调用 notifyItemUpdated() 根据 Pojo 对象中设置的标志临时隐藏列表中的项目

if(data?.hasVisible == false) {
            itemBinding.root.visibility = View.GONE
            itemBinding.root.layoutParams = RecyclerView.LayoutParams(0, 0)
        }else{
            itemBinding.root.visibility = View.VISIBLE
            itemBinding.root.layoutParams = RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT,
                RecyclerView.LayoutParams.WRAP_CONTENT)
        }

【讨论】:

  • 我不喜欢这个解决方案,但我没有找到任何其他解决方案!!!
【解决方案4】:

Adapter.notifyItemRemoved(position); appDatabase.userDao().deleteUser(user); 这对我有用!

【讨论】:

  • 如果我们不使用 Room 会怎样。
  • 是的,如果你知道对象但不知道位置怎么办
  • @Beyond Chen,使用 Room 是否只更新 UI 中被移除的项目或整个 RecyclerView?目前,在我的 Firestore 实现中,当我使数据无效时,它会更新整个 RecyclerView,而不仅仅是所需的一个单元格。如果 Room 解决了这个问题,我肯定会将 Room 连接到 Firestore。
  • 你通知适配器然后删除用户?这没有意义!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多