带有 DiffUtil 和 LiveData 的 ListAdapter 覆盖不附加的项目

ListAdapter with DiffUtil and LiveData overwriting items not appending

我用 DiffUtil 实现了 ListAdapter,但在添加新列表时遇到问题。它覆盖而不是附加到旧的。为了解决问题,我创建了一个新项目并用一些测试数据填充它。

这是我的代码:

MainActivity

private lateinit var binding: ActivityMainBinding
private val viewModel: ItemViewModel by lazy {
    ItemViewModel()
}
private val adapter: ItemAdapter by lazy {
    ItemAdapter()
}
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    viewModel.getItems()
    viewModel.items.observe(this, Observer { items ->
        adapter.submitList(items)
    })
    binding.recyclerView.adapter = adapter
    binding.fab.setOnClickListener {
        viewModel.getItems(9)
    }
}

ItemViewModel

class ItemViewModel: ViewModel() {
    private val repository = FakeRepository()
    private val _items: MutableLiveData<List<Item>> = MutableLiveData()
    val items: LiveData<List<Item>> = _items
    fun getItems(start: Int = 1) {
        viewModelScope.launch {
            val items = repository.getItems(start)
            _items.value = items
            /*val newItems = items.map { it.copy() }
            _items.postValue(newItems)*/
        }
    }
}

项目适配器

class ItemAdapter: ListAdapter<Item, ItemAdapter.ViewHolder>(DiffUtilCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(ItemRowBinding.inflate(LayoutInflater.from(parent.context),parent,false))
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

    class ViewHolder(private val binding: ItemRowBinding): RecyclerView.ViewHolder(binding.root) {
        fun bind(item: Item) {
            binding.apply {
                title.text = item.title
            }
        }
    }
    private class DiffUtilCallback: DiffUtil.ItemCallback<Item>() {
        override fun areItemsTheSame(oldItem: Item, newItem: Item) = oldItem.id == newItem.id

        override fun areContentsTheSame(oldItem: Item, newItem: Item) = oldItem == newItem

    }
}

项目

data class Item(
    val id: Int,
    val title: String,
    val timestamp: String
)

根据documentation

Submits a new list to be diffed, and displayed.

If a list is already being displayed, a diff will be computed on a background thread, which will dispatch Adapter.notifyItem events on the main thread.

因此,当您通过 LiveData 观察器提交新列表时,它是适配器的全新列表,因此它会覆盖当前项目而不附加它们。

如果要附加当前项,可以在适配器中创建一个方法将当前列表与新列表合并,并最终提交:

class ItemAdapter : ListAdapter<Item, ItemAdapter.ViewHolder>(DiffUtilCallback()) {

//......

    fun appendList(list: List<Item>) {
        val currentList = currentList.toMutableList() // get the current adapter list as a mutated list
        currentList.addAll(list)
        submitList(currentList)
    }

}

并将其应用于 activity 中的观察者回调:

viewModel.items.observe(this, Observer { items ->
      //  myAdapter.submitList(items) // send a brand new list
      myAdapter.appendList(items) // Update the current list
})