Home > front end >  How to use DiffUtils In RecyclerViewAdapter on Android
How to use DiffUtils In RecyclerViewAdapter on Android

Time:03-12

In my application I want use RecyclerView adapter and for set data I used DiffUtils.
I Want search data from server and then show it into RecyclerView!
I write below codes, but after search data show items overlay!
I want first clear previous data, then add new items!

Fragment codes :

    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()
            }
        }

Adapter codes:

    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)
}

How can I fix it?

CodePudding user response:

create a diff utils like this (can do in adapter 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()
        }
    }

then create two methods in your adapter

// 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)
    }

in fragment/activity do this

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)
  • Related