How to update a Recycler view with live data inside a fragment?

Viewed 6284

I want to update my Recycler View, so that whenever I delete a row from a table in a database, it updates the Recycler View at once without refreshing the fragment.

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

        var binding:FragmentDisplayBinding = DataBindingUtil.inflate(inflater,R.layout.fragment_display,container,false)

        var view:View = binding.root

        var new_task : FloatingActionButton = view.findViewById(R.id.add_newTask)





        var db = Room.databaseBuilder(context!!,tasksDb:: class.java,"mydb").allowMainThreadQueries().build()
        viewManager = LinearLayoutManager(context)

        recyclerView = view.findViewById(R.id.recyclerView)

        db.task().getAll().observe(this, Observer {
            this.myAdapter = myAdapter(it)
            recyclerView.adapter = myAdapter
            recyclerView.layoutManager = viewManager
        })

I believe I should not use the .observe() in the onCreateView() method. What changes should I implement in the code ??

2 Answers

I tried to find some example solutions on the Internet. There must be one, but couldn't find any. I find many of them are too short or too detailed. So I will drop here just exactly what you need. There is a standardized pattern involving RecyclerView + LiveData, so just follow this pattern for all your RecyclerView + LiveData usages.

Fragment:

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

    ...

    val recyclerView = view.findViewById(R.id.recyclerView)
    val myAdapter = MyAdapter()
    recyclerView.adapter = myAdapter
    // recyclerView.layoutManager = LinearLayoutManager(context) // You need this only if you haven't set it in xml

    db.task().getAll().observe(viewLifecycleOwner, Observer {
        myAdapter.submitList(it)
    })
}

Few important changes made here:

  • You must .observe() in onCreateView(). Not just for this specific case, but in general you will never need to call .observe() in any other places if you are using LiveData correctly.
  • viewLifecycleOwner is the correct LifecycleOwner to use for observing a LiveData. (Unless you create a custom one.)
  • Depends on the use case but generally instantiate one adapter per RecyclerView, even if your data changes over time. You should swap the data, not the whole adapter.


MyAdapter:

MyAdapter should implement the .submitList() function that will be used by the view

class MyAdapter: RecyclerView.Adapter<ViewHolder>() {

    val myData = mutableListOf<Data>()

    fun submitList(newData: List<Data>) {
        myData.clear()
        myData.addAll(newData)
        notifyDataSetChanged()
    }
}

Note that notifyDataSetChanged() is the one actually signals the adapter to update the view.


Improvements:

I think above solution is good enough for your problem, given that your list is not too big or too frequently updated. If you want further improvement in performance and/or readability, explore following:

  • Use Paging library to paginate long or infinite list.
  • Diff in a worker thread using DiffUtil as suggested in the comment.
  • Binding library to reduce some boiler plates

May be this will help.

To refresh your items in recycler you need to use below code

myAdapter. notifyDataSetChanged(); recyclerview.setAdapter(myAdapter);

In your case write this method immediately after your logic to delete item of recycler view.

Related