我们如何使用Paging 3安卓系统来更改加载的项目



我正在从网络加载帖子,为此我使用Paging 3,但现在的问题是我的列表项包含Like/Dislike按钮,假设点击了Like,那么我如何在不重新加载整个数据集的情况下更新该项的数据?

我已经阅读了这个android页面列表更新,但它似乎是为旧的分页2或1,那么在Paging 3中实现这一点的完美方法是什么

在Paging3中,您仍然需要依靠PagingSource.invalidate来提交更新,这与其说是关于不变性,不如说是关于拥有一个单一的真相来源。

通常,正确的方法是更新支持数据集并调用invalidate,这将触发REFRESH+DiffUtil,该命令不会导致任何UI更改,但可以保证,如果删除并重新蚀刻该页面,则加载的页面仍然是最新的。最简单的方法是使用一个PagingSource实现,该实现已经内置了自失效功能,就像Room提供的那样,只需在单击"喜欢/不喜欢"按钮时更新相应的行。

有一个开放的bug跟踪工作,以支持对列表的高度频繁、细粒度的更新,并使用Flow<gt;,如果这是您的用例,您可以在此处遵循:https://issuetracker.google.com/160232968

我用下面的机制克服了这个挑战。维护内部哈希映射以保存键和对象,将此内部哈希映射保存在您的pagedlist适配器中。随着列表的滚动,您将使用其something unique键将远程喜欢/不喜欢添加到内部哈希图中作为初始状态,因为该键是唯一的,所以您不会重复,然后您将此内部哈希图用于更新UI。

点赞和不喜欢的onClick监听器将更新此内部哈希图。内部hashmap也是UI更新的参考。

解决方案很简单——在另一个内部哈希图上收集有用的数据,以便稍后操作。

我找到了一个可以实现这一点的解决方案,给出了我正在使用的代码库的一些背景:

  • 我有一个PagingDataAdapter(Pagination3.0适配器(作为回收器视图适配器
  • 我有一个片段的视图模型
  • 我有一个返回分页数据流的存储库
  • 并将此流作为liveData公开给fragment

存储库代码:

override fun getPetsList(): Flow<PagingData<Pets>> {
return Pager(
config = PagingConfig(
pageSize = 15,
enablePlaceholders = false,
prefetchDistance = 4
),
pagingSourceFactory = {
PetDataSource(petService = petService)
}
).flow
}

视图模型代码:

// create a hashmap that stores the (key, value) pair for the object that have changed like (id:3, pet: fav=true .... )
viewModelScope.launch {
petRepository.getPetsList()
.cachedIn(viewModelScope)
.collect {
_petItems.value = it
}
}

现在片段的代码在哪里映射和所有的魔术发生

viewModel.petItems.observe(viewLifecycleOwner) { pagingData ->
val updatedItemsHashMap = viewModel.updatedPetsMap
val updatedPagingData = pagingData.map { pet ->
if (updatedItemsHashMap.containsKey(pet.id))
updatedItemsHashMap.getValue(pet.id)
else
pet
}
viewLifecycleOwner.lifecycleScope.launch {
petAdapter.submitData(updatedPagingData)
}
}

所以这就是实现这一点的方法,关键是对从存储库发出的pagingData进行映射。

不起作用的东西:

_petItems.value = PagingData.from(yourList)

这不会起作用,因为根据文档,这是用于静态列表的,并且您会失去分页3.0附带的分页功能。因此映射pagingData似乎是唯一的方法。

要在没有房间数据库的情况下使用Paging 3实现这一点,我们可以在ViewModel中创建一个可变的数据流列表,其中包含我们想要操作的项目。当观察寻呼3的流时,我们可以将其与本地流相结合,找到我们想要更改的项。然后,我们可以在将其提交给视图进行观察之前对其进行更改。

下面是一个简化的ViewModel示例,它演示了这个解决方案:

class ExampleViewModel(
private val likePostUseCase: LikePostUseCase,
private val unlikePostUseCase: UnlikePostUseCase,
private val getPaginingPostsUseCase: GetPostsUseCase
) : ViewModel() {
private val _localDataList = MutableStateFlow(listOf<MyData>())
// Observe the Paging 3 Flow and combine it with the local Flow
val combinedDataList = getPaginingPostsUseCase().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 when the post is liked
fun likePost(item: MyData) {
likePostUseCase(item.id)
val updatedItem = item.copy(isLiked = true) // or use the returned item from likePostUseCase.
val newList = _localDataList.value.filterNot { it.id == updatedItem.id } // remove old version if any.
_localDataList.value = newList + updatedItem // this triggers flow combine and updates your recyclerview without loading all pagination data again.
}
// Method to update the item in the local Flow when the post is unliked
fun unlikePost(item: MyData) {
unlikePostUseCase(item.id)
val updatedItem = item.copy(isLiked = false)
val newList = _localDataList.value.filterNot { it.id == updatedItem.id } // remove old version if any.
_localDataList.value = newList + updatedItem
}
}

相关内容

最新更新