Android 如何在 RecyclerView Adapter 中使用 DiffUtils
How to use DiffUtils In RecyclerViewAdapter on Android
在我的应用程序中,我想使用 RecyclerView
适配器,对于设置数据,我使用 DiffUtils
。
我要从服务器搜索数据,然后将其显示到 RecyclerView
!
我写了下面的代码,但在搜索数据后显示项目叠加!
我要先清除之前的数据,再添加新的项目!
片段代码:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//InitViews
binding.apply {
searchEdt.addTextChangedListener {
val search = it.toString()
if (search.isNotEmpty()) {
viewModel.searchList.observe(viewLifecycleOwner) { response ->
lastMoviesAdapter.differ.submitList(response.data)
searchMoviesRecycler.initRecycler(LinearLayoutManager(requireContext()), lastMoviesAdapter)
}
viewModel.loadSearchMovies(search)
} else {
Snackbar.make(view, getString(R.string.fillAllFields), Snackbar.LENGTH_SHORT).show()
}
}
适配器代码:
class LastMoviesAdapter @Inject constructor() : RecyclerView.Adapter<LastMoviesAdapter.ViewHolder>() {
private lateinit var binding: ItemHomeMoviesLastBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
binding = ItemHomeMoviesLastBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder()
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(differ.currentList[position])
holder.setIsRecyclable(false)
}
override fun getItemCount() = differ.currentList.size
inner class ViewHolder : RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SetTextI18n")
fun bind(item: Data) {
binding.apply {
moviePosterImg.load(item.poster) {
crossfade(true)
crossfade(1000)
}
movieNameTxt.text = item.title
movieRateTxt.text = item.imdbRating
movieCountryTxt.text = item.country
movieYearTxt.text = item.year
}
}
}
private val differCallback = object : DiffUtil.ItemCallback<Data>() {
override fun areItemsTheSame(oldItem: Data, newItem: Data): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Data, newItem: Data): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this, differCallback)
}
我该如何解决?
像这样创建一个 diff utils(可以在适配器中做 class)
class DiffUtilCallback(private val oldList: List<Any>, private val newList: List<Any>) :
DiffUtil.Callback() {
// old size
override fun getOldListSize(): Int = oldList.size
// new list size
override fun getNewListSize(): Int = newList.size
// if items are same
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldList[oldItemPosition]
val newItem = newList[newItemPosition]
return oldItem.javaClass == newItem.javaClass
}
// check if contents are same
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldList[oldItemPosition]
val newItem = newList[newItemPosition]
return oldItem.hashCode() == newItem.hashCode()
}
}
然后在您的适配器中创建两个方法
// set data
fun setData(data: List<Any>) {
this.data = data.toMutableList()
}
// add new data
fun setNewData(newData: List<Any>) {
val diffCallback = DiffUtilCallback(data, newData)
val diffResult = DiffUtil.calculateDiff(diffCallback)
data.clear()
data.addAll(newData)
diffResult.dispatchUpdatesTo(this)
}
在 fragment/activity 中执行此操作
adapter = AdapterDual(recycler, lifecycleScope) // init adapter
adapter.setData(list) // set data
recycler.layoutManager = LinearLayoutManager(activity)
recycler.adapter = adapter // set adapter on recycler
// and when you load new data or replace it
adapter.setNewData(newList)
remember that if you are loading more items then newList
will contain both the previous items as well as loaded items
在我的应用程序中,我想使用 RecyclerView
适配器,对于设置数据,我使用 DiffUtils
。
我要从服务器搜索数据,然后将其显示到 RecyclerView
!
我写了下面的代码,但在搜索数据后显示项目叠加!
我要先清除之前的数据,再添加新的项目!
片段代码:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//InitViews
binding.apply {
searchEdt.addTextChangedListener {
val search = it.toString()
if (search.isNotEmpty()) {
viewModel.searchList.observe(viewLifecycleOwner) { response ->
lastMoviesAdapter.differ.submitList(response.data)
searchMoviesRecycler.initRecycler(LinearLayoutManager(requireContext()), lastMoviesAdapter)
}
viewModel.loadSearchMovies(search)
} else {
Snackbar.make(view, getString(R.string.fillAllFields), Snackbar.LENGTH_SHORT).show()
}
}
适配器代码:
class LastMoviesAdapter @Inject constructor() : RecyclerView.Adapter<LastMoviesAdapter.ViewHolder>() {
private lateinit var binding: ItemHomeMoviesLastBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
binding = ItemHomeMoviesLastBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder()
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(differ.currentList[position])
holder.setIsRecyclable(false)
}
override fun getItemCount() = differ.currentList.size
inner class ViewHolder : RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SetTextI18n")
fun bind(item: Data) {
binding.apply {
moviePosterImg.load(item.poster) {
crossfade(true)
crossfade(1000)
}
movieNameTxt.text = item.title
movieRateTxt.text = item.imdbRating
movieCountryTxt.text = item.country
movieYearTxt.text = item.year
}
}
}
private val differCallback = object : DiffUtil.ItemCallback<Data>() {
override fun areItemsTheSame(oldItem: Data, newItem: Data): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Data, newItem: Data): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this, differCallback)
}
我该如何解决?
像这样创建一个 diff utils(可以在适配器中做 class)
class DiffUtilCallback(private val oldList: List<Any>, private val newList: List<Any>) :
DiffUtil.Callback() {
// old size
override fun getOldListSize(): Int = oldList.size
// new list size
override fun getNewListSize(): Int = newList.size
// if items are same
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldList[oldItemPosition]
val newItem = newList[newItemPosition]
return oldItem.javaClass == newItem.javaClass
}
// check if contents are same
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldList[oldItemPosition]
val newItem = newList[newItemPosition]
return oldItem.hashCode() == newItem.hashCode()
}
}
然后在您的适配器中创建两个方法
// set data
fun setData(data: List<Any>) {
this.data = data.toMutableList()
}
// add new data
fun setNewData(newData: List<Any>) {
val diffCallback = DiffUtilCallback(data, newData)
val diffResult = DiffUtil.calculateDiff(diffCallback)
data.clear()
data.addAll(newData)
diffResult.dispatchUpdatesTo(this)
}
在 fragment/activity 中执行此操作
adapter = AdapterDual(recycler, lifecycleScope) // init adapter
adapter.setData(list) // set data
recycler.layoutManager = LinearLayoutManager(activity)
recycler.adapter = adapter // set adapter on recycler
// and when you load new data or replace it
adapter.setNewData(newList)
remember that if you are loading more items then
newList
will contain both the previous items as well as loaded items