如何使用Paging 3库更新单个项目

19

我正在尝试使用来自Paging 3库的PagingAdapter找到一种更新RecyclerView单个项的方法。我只找到了一种用PagingAdapter.refresh()方法的方式。但是这个方法强制从网络加载所有列表。有人知道如何在不从网络加载所有页面的情况下实现它吗?

4个回答

21

目前,更新后备数据集的唯一方法是使列表失效并重新加载。对于使用缓存层(在数据库中,如room,或内存中)的分层源,这通常是一个可以接受的便宜选择,尽管仍在进行支持更精细的更新的工作(请参见https://issuetracker.google.com/160232968)。

就分层源而言,您需要将网络调用移动到RemoteMediator中,并在Pager的构造函数中注册它,然后将网络获取缓存到数据库中,例如Room(它可以为您生成一个PagingSource实现),或者自己编写一个内存中的实现。

codelabDAC文档是此方面的良好资源,并提供指导您的代码示例!


自定义的内存存储将被RemoteMediator和自定义的PagingSource同时使用吗?我认为自定义的PagingSource会观察内存存储中的更改,然后使其无效。当单个项目的更新任务异步发生并且用户滚动RecyclerView到不再屏幕上的位置时,这仍然能正常工作吗? - masterwok
1
在失效时,分页会使用以用户当前位置为中心的键通过 PagingSource.getRefreshKey 重新加载。新一代通过 DiffUtil 动态插入,所以这应该是可以工作的。 - dlam
1
你的RemoteMediator不应该消耗缓存,只需写入它(除了跟踪下一个要加载的远程键)。 - dlam

2

1
请注意,此函数位于适配器内部。 - Javlon

0
为了实现这个目标(注意:这里我不使用数据库作为缓存,只使用远程),我们可以在ViewModel中创建一个可变的数据列表Flow,其中包含我们想要操作的项。观察Paging 3的Flow时,我们可以将其与本地Flow结合起来找到要更改的项。然后,在提交给视图进行观察之前,我们可以对其进行更改。
以下是演示此解决方案的简化ViewModel示例:
class ExampleViewModel : ViewModel() {

    private val _localDataList = MutableStateFlow(listOf<MyData>())

    // Observe the Paging 3 Flow and combine it with the local Flow
    val combinedDataList = paging3Flow.cachedIn(viewModelScope).combine(_localDataList) { paging, local  ->
        // Find and update the desired item in the list
        paging.map {
            if (it.id == local.id) local
            else  it
        }
    }

    // Method to update the item in the local Flow
    fun updateItem(item: MyData) {
        val updatedItem = getUpdatedItemFromServerUseCase()
        val newList = _localDataList.value.filterNot { it.id == updatedItem.id } // remove old version if any.
        _localDataList.value = newList + updatedItem
    }
}


如果您想从列表中删除项目,可以创建一个新的数据类,其中包含具有更新和删除值的updateType枚举的项。根据更新类型,您可以相应地映射PagingData。
以下是如何使用updateType枚举的示例:
enum class UpdateType {
    UPDATE, REMOVE
}

data class UpdateData(
    val updateType: UpdateType,
    val item: MyData
)

class ExampleViewModel : ViewModel() {

    private val _localDataList = MutableStateFlow(listOf<UpdateData>())

    // Observe the Paging 3 Flow and combine it with the local Flow
    val combinedDataList = paging3Flow.combine(_localDataList.) { paging, local  ->
        // Find and update or remove the desired item in the list
        paging.map {
            local.find { localItem -> localItem.item.id == it.id }?.let { localItem ->
                when (localItem.updateType) {
                    UpdateType.UPDATE -> localItem.item
                    UpdateType.REMOVE -> null
                }
            } ?: it
        }.filter { it!=null }
    }

    // Method to remove the item from the local Flow
    fun updateItem(item: MyData) {
        removeItemFromServerUseCase()
        val newList = _localDataList.value.filterNot { it.item.id == item.id } // remove old version if any.
        _localDataList.value = newList + UpdateData(UpdateType.REMOVE, updatedItem)
    }
}


请注意,updateremove操作非常容易实现,但是add更难(使用了insertFooterItem)。在https://sourcediving.com/crud-operations-with-the-new-android-paging-v3-5bf55110aa4d上可以看到一个很好的例子。 - CoolMind

-1
(adapterComment.snapshot().items as MutableList<Model>)[position].likeStatus = 0
adapterComment.notifyItemChanged(position)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接