我使用 RecyclerView 和 DiffUtil 来管理数据列表中的更改。我面临的问题是,当尝试使用 AsyncListDiffer 和 DiffUtil 将多个项目连续插入我的适配器时,并非所有项目都在 RecyclerView 中正确显示。有时仅显示最后插入的项目,或仅显示部分项目。
这是我在适配器中处理项目插入的方式:
// No problem showing everything at the beginning
fun addAll(items:List<ItemEntity>){
asyncListDiffer.submitList(items)
}
fun add(item: ItemEntity) {
val updateList = asyncListDiffer.currentList.toMutableList()
updateList.add(item)
asyncListDiffer.submitList(updateList.toList())
}
我的 DiffUtil 实现
private class DiffCallback:DiffUtil.ItemCallback<ItemEntity>(){
override fun areItemsTheSame(oldItem: ItemEntity, newItem: ItemEntity): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: ItemEntity, newItem: ItemEntity): Boolean {
return oldItem == newItem
}
}
我的视图模型实现的一部分
@HiltViewModel
class MainViewModel @Inject constructor(private val repository:MainRepository):ScopedViewModel() {
private var _allItems:MutableLiveData<List<ItemEntity>> = MutableLiveData()
val allItems:LiveData<List<ItemEntity>> = _allItems
private var _itemInserted:MutableLiveData<ItemEntity> = MutableLiveData()
val itemInserted:LiveData<ItemEntity> = _itemInserted
init{
initScope()
}
// Called when loading the application
fun fetchAllItems(){
launch{
_allItems.value=repository.fetchAllItems()
}
}
fun saveNewItem(itemEntity: ItemEntity){
launch {
val idInserted=repository.saveNewItem(itemEntity)
getItemById(idInserted)
}
}
/* Every time I add a new record or multiple records I usually address selected files from mobile storage
*/
fun getItemById(itemId:Long){
launch {
_itemInserted.value=repository.fetchItemById(itemId)
}
}
override fun onCleared() {
destroyScope()
super.onCleared()
}
在我的片段中,第一次加载时所有元素都正确显示,没有问题。 仅当我稍后向数据库添加更多记录以将它们添加到我的适配器时,观察者 itemInserted 才会启动。
private fun setUpObservers(){
mainViewModel.fetchAllSong()
mainViewModel.allItems.observe(viewLifecycleOwner){
if (it.isNotEmpty()) {
adapter.addAll(it)
}
}
mainViewModel.itemInserted.observe(viewLifecycleOwner){item->
item?.let{
adapter.add(item)
}
}
}
添加单个记录时,它通常会添加到我的列表中,但当我连续添加多个记录时,就会出现问题。
举个例子,当选择两个或多个文件并保存它们的地址时,itemInserted观察者正确返回每条记录,问题是适配器大多数时候只显示最后添加的元素,其他时候则显示所有元素。
private fun mActivityResult(){
launcherOpenMultipleDocs= registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()){uris->
uris.forEach {uri->
val realPathFromFile = getRealPathFromURI(uri!!, requireContext())
mainViewModel.saveNewItem(
ItemEntity(
pathLocation = realPathFromFile,
timestamp = Date().time
)
)
}
}
}
我不是 Android 专家,所以我可以从这种行为中推断出一点是,通过快速向适配器添加多个项目,并且由于它在主线程之外对新元素进行比较,因此肯定存在一些问题同步,我不知道。 我将继续调查更多。
如何确保 DiffUtil 正确处理 RecyclerView 中的多个连续插入?
使用 AsyncListDiffer 和 DiffUtil 来管理快速项目插入时,我还应该注意其他注意事项吗?
欢迎任何帮助,谢谢。
我最终解决了这个问题,每次添加新记录时都会带回所有记录并将整个新列表发送到适配器。
在MainViewModel类中
fun saveNewItem(itemEntity: ItemEntity){
launch {
val idInserted=repository.saveNewItem(itemEntity)
// I just changed this line
fetchAllItems()
}
}
在片段中,整个列表将再次添加到适配器中
mainViewModel.allItems.observe(viewLifecycleOwner){
if (it.isNotEmpty()) {
adapter.addAll(it)
}
}
总而言之,尽管在仅添加一个元素时调用整个列表一开始似乎有些多余,但 DiffUtil 的效率使其成为保持更新 RecyclerView 一致性和准确性的最佳实践。我必须感谢@Pawel 对此事的澄清。如果有人遇到同样的问题,我希望这会有所帮助。