问题描述
我正在寻找一种方法来更新 Paging 3 库中 PagingDataAdapter
中的特定项目。目前推荐的方法似乎是使 PagingSource
无效,但这会导致适配器再次获取整个数据集,这不仅效率低下,而且还显示了我的加载微调器。
但是,我注意到我可以使用 peek()
方法访问和修改适配器中的项目,而且它似乎工作得很好。我在这里错过了什么吗?这会在某些情况下分崩离析吗?我知道保持数据类不可变是一种很好的做法,但这种方法让我的生活变得更轻松。
这是我的用法示例,它似乎工作得很好:
viewmodel.chatMessageUpdateEvents.collect { messageEvent ->
when (messageEvent) {
is FirestoreChatMessageListener.ChatMessageUpdateEvent.MessageUpdate -> {
val update = messageEvent.chatMessage
val historyAdapterItems = chatMessagesHistoryAdapter.snapshot().items
val updatedMessage =
historyAdapterItems.find { chatMessage ->
chatMessage.documentId == messageEvent.chatMessage.documentId
}
if (updatedMessage != null) {
val messagePosition = historyAdapterItems.indexOf(updatedMessage)
chatMessagesHistoryAdapter.peek(messagePosition)?.unsent = update.unsent
chatMessagesHistoryAdapter.peek(messagePosition)?.imageUrl = update.imageUrl
chatMessagesHistoryAdapter.notifyItemChanged(messagePosition)
}
}
}
}
解决方法
我在单独的评论中回复,但想在这里发帖以提高知名度。
这真的是不推荐的,并且完全不支持使用分页。
如果 Pager().flow()
尚未清除(例如 ViewModel 尚未清除),则恢复状态的主要方法之一是通过 .cachedIn(scope)
方法,该方法将缓存溢出-您的情况下的日期数据。这也是多播(使 PagingData 中加载的数据可重用)以用于流操作(例如 .combine()
)的唯一方法,允许您将转换与外部信号混合。
您还需要处理动态加载之间的竞争,如果在追加完成的同时收到 messageEvent 会发生什么?在这种情况下谁会赢?是否有可能在 .snapshot()
之间插入一个新页面,因此您的通知位置不再正确?
一般来说,拥有单一事实来源要简单得多,这是推荐的路径,因此建议始终在每次支持数据集更新时失效。
Paging 的问题跟踪器中有一个开放的 FR 来支持 Flow<Item>
或 Flow<Page>
样式数据以允许粒度更新,但这肯定是一个更远的未来:https://issuetracker.google.com/160232968