3

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?

Dr.KeyOk
  • 608
  • 1
  • 6
  • 13

1 Answers1

5

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)

remember that if you are loading more items then newList will contain both the previous items as well as loaded items

Saksham Khurana
  • 872
  • 13
  • 26
  • Thanks my friend for your help. but how can I use this in Fragment? In fragment I used `setData` function or `setNewData` ? – Dr.KeyOk Mar 12 '22 at 05:05
  • in new data you will use `setData`... and when you get more data or need to replace data... use the `setNewData` .. check updated answer – Saksham Khurana Mar 12 '22 at 06:50