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