带有 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
)
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
})
我用 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
)
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
})