'Firebase recyclerview always refreshes and losses its scroll position when starting new activity and returning

My Firebase recycler view always refreshes and loses its scroll position when opening new activity and coming back. Tried multiple solution in Stack Overflow but none woks for me. Here is my code

class HomeActivity : AppCompatActivity() {
   private var layoutManager:RecyclerView.LayoutManager? = null
    private var recyclerViewState: Parcelable? = null
    private var recyclerView:RecyclerView? = null

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_home)
recyclerView = findViewById(R.id.recycler_menu)
        layoutManager = LinearLayoutManager(this)
        recyclerView!!.layoutManager = layoutManager
}
override fun onStart() {
        super.onStart()
        var productRef: DatabaseReference = FirebaseDatabase.getInstance().reference.child(PRODUCTS_DB_NAME).child(
            PRODUCT_STATE_ACTIVE)
        var options:FirebaseRecyclerOptions<Products>? = null
            options = FirebaseRecyclerOptions.Builder<Products>().setQuery(productRef, Products::class.java).
            setLifecycleOwner(this).build()
        val adapter = object : FirebaseRecyclerAdapter<Products, ProductViewHolder>(options) {
            override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
                return ProductViewHolder(LayoutInflater.from(parent.context)
                    .inflate(R.layout.product_items_layout, parent, false))
            }

            protected override fun onBindViewHolder(holder: ProductViewHolder, position: Int, model: Products) {
                holder.txtProductName.text = model.pname
                holder.txtProductDescription.text = model.description
                holder.txtProductPrice.text = "Price = ₹ " + model.price.toString()
                val context = holder.itemView.context
                Picasso.with(this@HomeActivity).load(model.image).networkPolicy(NetworkPolicy.OFFLINE).into(holder.imageView,
                    object: Callback {
                        override fun onSuccess() {
                        }

                        override fun onError() {
                            Picasso.with(this@HomeActivity).load(model.image).into(holder.imageView)
                        }
                    })
                holder.itemView.setOnClickListener {
                    val intent:Intent = Intent(this@HomeActivity, ProductDetailsActivity::class.java)
                    intent.putExtra("pid", model.pid)
                    startActivity(intent)
                }
            }
        }
        val recyclerView:RecyclerView = findViewById(R.id.recycler_menu)
        recyclerView.setAdapter(adapter)
        adapter.startListening()
    }
override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        recyclerViewState = recyclerView!!.getLayoutManager()!!.onSaveInstanceState();

    }

    override fun onResume() {
        super.onResume()
        recyclerView!!.getLayoutManager()!!.onRestoreInstanceState(recyclerViewState);
    }
    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
        super.onRestoreInstanceState(savedInstanceState)
        recyclerView!!.getLayoutManager()!!.onRestoreInstanceState(recyclerViewState);
    }
}


Solution 1:[1]

I use this method in my code check it

 private fun updateRecycler(){
    val recyclerViewState = recyclerView.layoutManager?.onSaveInstanceState()
    recyclerView.adapter.notifyDataSetChanged()
    recyclerView.layoutManager?.onRestoreInstanceState(recyclerViewState)
}

I see you use this method when you update data

recyclerView.setAdapter(adapter)

That is bad idea. you must set adapter once and change data every time. you need rethink on your code

Solution 2:[2]

You have to save your state of recycler view scroll view, if you want to achieve what you want here.

Save state of recyclerview scrollView

1. Make a variable

private Parcelable scroll_state;

2. save state in onPause()

scroll_state = linearLayoutManager.onSaveInstanceState();

3. restore state in onResume()

linearLayoutManager.onRestoreInstanceState(scroll_state);

Note : Here, linearlayoutmanager is the layoutmanager of your recyclerview.

Solution 3:[3]

I solved my problem with a simpler solution.

I just called adapter.startListening(); in onViewCreated() instead of onStart and called adapter.stopListening(); in onDestroyView() instead of onStop() That prevented the entire list from regenerating while coming back from the next activity and thus retained the scroll position where it was previously.

for more details please visit: https://github.com/firebase/FirebaseUI-Android/issues/998#issuecomment-342413662

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 waqas Ahmad