ListAdapter submitlist not update after deleting the data instead its giving me duplicate data

481 Views Asked by At

when i try to delete first row i get first row back and with duplicate second row enter image description here

after delete any row from the list gives me duplicate data like this enter image description here

This is my Adapter class. On my deleteItem function position is passed from fragment class and it is supposed to delete an item from the given position and update the list but its rendering the duplicate data.

class MyListAdapter :ListAdapter<Article,MyListAdapter.MyViewHolder>(MyDiffUtil()) {



    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.recycler_item,parent,false)
       return MyViewHolder(view)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {

        val item = getItem(position)
        holder.onBind(item)



        // to click each item of list
        holder.itemView.setOnClickListener {
            onItemClickListener?.let {it(item) }

        }
    }




    class MyViewHolder(itemView :View) : RecyclerView.ViewHolder(itemView)
    {
        fun onBind(article: Article)  = with(itemView)
        {

            Glide.with(this)
                .load(article.urlToImage)
                .error(R.drawable.notfound)
                .into(imageView)

            webSource.text = article.source?.name
            newsDate.text = article.publishedAt
            newsTitle.text = article.title
            newsDescription.text = article.description

        }

    }

    // lamda function for handling web view
     private var onItemClickListener : ((Article) -> Unit)? = null

    fun setOnItemClickListener(listener : (Article) ->Unit)
    {
        onItemClickListener = listener
    }

    // implementing diffutil class
    class MyDiffUtil : DiffUtil.ItemCallback<Article>()
    {
        override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
            return  oldItem.url == newItem.url
        }

        override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
            return oldItem == newItem
        }

    }

fun deleteItem(pos : Int)
    {
        var myl = ArrayList<Article>()

       val currentList= currentList.toMutableList()
        currentList.removeAt(pos)

        myl.addAll(currentList)

        submitList(myl)
       


    }


}

`

I tried to delete the saved news from the ListAdapter and update the recycler view with animation of DiffUtill class but its not updating the recycler view and giving duplicate data . How can i delete data with diffutil animation as its normal way. Thanks in advance.

this is my fragment

package com.example.news.Fragments

class SavedNews : Fragment() {

    lateinit var mymainViewModel: MainViewModel
    lateinit var databaseObject: MyDataBase
    lateinit var myAdapter: MyListAdapter
    lateinit var convertedArticleList : ArrayList<Article>




    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {


        myAdapter = MyListAdapter()
        convertedArticleList = ArrayList()
        return inflater.inflate(R.layout.fragment_saved_news, container, false)
    }



    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        savedNewsRecyclerView.layoutManager = LinearLayoutManager(activity,LinearLayoutManager.VERTICAL,
        false)
        savedNewsRecyclerView.adapter = myAdapter


        ItemTouchHelper(object :ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.RIGHT){
            override fun onMove(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder,
                target: RecyclerView.ViewHolder
            ): Boolean {
                // this method is called
                // when the item is moved.
                return true
            }


            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {

                // this method is called when we swipe our item to right direction.
                // on below line we are getting the item at a particular position.

                val deletedCourse: Article =
                    convertedArticleList.get(viewHolder.adapterPosition)


               myAdapter.deleteItem(viewHolder.adapterPosition)


                mymainViewModel.deleteSavedNews(deletedCourse.id!!)


//                myAdapter.notifyItemRemoved(viewHolder.adapterPosition)
//                myAdapter.submitList(myCurrentList)





//                Snackbar.make(savedNewsRecyclerView,"Deleted" + deletedCourse.title,
//                Snackbar.LENGTH_LONG).setAction(
//                    "Undo",
//                    View.OnClickListener {
//
//                        convertedArticleList.add(position,deletedCourse)
//                        myAdapter.notifyItemInserted(position)
//                    }
//                ).show()


            }

        }).attachToRecyclerView(savedNewsRecyclerView)
    }




    override fun onResume() {
        super.onResume()


        Log.d("LIFE","ON Resume")

        val myInterfaceObject = ApiInterface.MyObject.getInstance()
        databaseObject = MyDataBase.MyObjectDB.getDBInstance(activity as MainActivity)

        val myRepository = Repository(myInterfaceObject, databaseObject)

        mymainViewModel = ViewModelProvider(
            this,
            MainViewModelFactory(myRepository)
        ).get(MainViewModel::class.java)


        //listAdapter things





        // show saved news in savednews fragment
        lifecycleScope.launch(Dispatchers.Main) {

            //abstract data from saved room database and converting likedartcile datacass object to
            // Artticle data class article
            mymainViewModel.abstractSavedNews().observe(viewLifecycleOwner, Observer {

                it.forEach { eachLikedArticle ->

                    val obj = toArticle(eachLikedArticle)
                    convertedArticleList.add(obj)
                }

                myAdapter.submitList(convertedArticleList)

            })


            //clicking the item of save news
            myAdapter.setOnItemClickListener {

                val bundle = Bundle().apply {

                    putSerializable("article", it)
                }


                convertedArticleList.clear()
                findNavController().navigate(R.id.action_savedNews_to_article, bundle)
            }

        }

    }



   private fun toArticle(rawObject: LikedArticle) = Article(
        rawObject.author, rawObject.content,
        rawObject.description, rawObject.publishedAt, rawObject.source, rawObject.title,
        rawObject.url, rawObject.urlToImage, rawObject.id
    )
}
1

There are 1 best solutions below

3
moondev On

There is not enough information to actually replicate how you're trying to use this in your Fragment/Activity but without changing your code too much, this works (note I used view binding):

class MyListAdapter :
    ListAdapter<Article, MyViewHolder>(MyDiffUtil()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = MyViewHolder(
        RecyclerItemBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        )
    )

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val item = getItem(position)
        holder.onBind(item)
    }
    
    fun deleteItem(pos: Int) {
        var myl = ArrayList<Article>()
        val currentList = currentList.toMutableList()
        currentList.removeAt(pos)
        myl.addAll(currentList)
        submitList(myl)
    }
}

class MyViewHolder(private val binding: RecyclerItemBinding) : RecyclerView.ViewHolder(binding.root) {
    fun onBind(article: Article) = with(binding) {
        textView.text = article.url
    }
}

class MyDiffUtil : DiffUtil.ItemCallback<Article>() {
    override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
        return oldItem.url == newItem.url
    }

    override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
        return oldItem == newItem
    }
}

Overall this should work. You can also refactor deleteItem to something more meaningful:

fun deleteItem(pos: Int) {
        val oldList = currentList.toMutableList()
        oldList.removeAt(pos)
        val updatedList = oldList
        submitList(updatedList)
    }