RecyclerView Adapter 中的 DiffUtil 在连续插入多个项目时不显示所有项目

问题描述 投票:0回答:1

我使用 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 专家,所以我可以从这种行为中推断出一点是,通过快速向适配器添加多个项目,并且由于它在主线程之外对新元素进行比较,因此肯定存在一些问题同步,我不知道。 我将继续调查更多。

  1. 如何确保 DiffUtil 正确处理 RecyclerView 中的多个连续插入?

  2. 使用 AsyncListDiffer 和 DiffUtil 来管理快速项目插入时,我还应该注意其他注意事项吗?

欢迎任何帮助,谢谢。

android kotlin android-recyclerview android-diffutils android-listadapter
1个回答
0
投票

我最终解决了这个问题,每次添加新记录时都会带回所有记录并将整个新列表发送到适配器。

在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 对此事的澄清。如果有人遇到同样的问题,我希望这会有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.