'Recyclerview getting refreshed after come back from another screen - Android navigation

I am having a product listing page. The recyclerview is filled with data from the Firebase firestore. When I click on any product, it will go to the details page.

view.findNavController().navigate(R.id.action_nav_products_to_productDetailFragment, bundle)

But if I click the back button, I am calling popBackStack() and come back to previous screen and it getting reaload.

findNavController().popBackStack()

The same behavior is happening if I click the system back button too.

I checked some other Stackoverflow posts and followed some answers. But nothing helps.

The one which I tried was, in onCreateView I check for the adapter initialization and If already initialized, it will not set the adapter of recylerview. But after applied this logic, I came to know that even if I am not setting the adapter to recyclerview, it will automatically reload.

I checked the samples provided by the google documentation which is working fine. But I can see the only difference in my case is Firestore.

implementation 'com.google.firebase:firebase-firestore-ktx:22.1.2'
implementation 'com.google.firebase:firebase-database:19.7.0'
implementation 'com.google.firebase:firebase-storage-ktx:19.2.2'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation "androidx.navigation:navigation-fragment:$2.4.0-alpha01"
implementation "androidx.navigation:navigation-ui:$2.4.0-alpha01"
implementation "androidx.navigation:navigation-fragment-ktx:$2.4.0-alpha01"
implementation "androidx.navigation:navigation-ui-ktx:$2.4.0-alpha01"

I tried a stable version of navigation too. But same behavior.

Base fragment code

abstract class BaseFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        parent: ViewGroup?,
        savedInstanseState: Bundle?
    ): View? {
        val view =  getFragmentView(inflater, parent, savedInstanseState)
        view.findViewById<Toolbar>(R.id.toolbar)?.let {
            it.title = getTitle()
            it.setNavigationOnClickListener { (activity as HomeActivity).openDrawer() }
        }
        return view
    }

    abstract fun getFragmentView(
        inflater: LayoutInflater,
        parent: ViewGroup?,
        savedInstanceState: Bundle?
    ): View

    abstract fun getTitle():String
}

List fragment code below

class ProductsFragment : BaseFragment() {

    private val productsViewModel: ProductsViewModel by activityViewModels()
    private val categoryViewModel: CategoryViewModel by activityViewModels()

    override fun getFragmentView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        setUpProductsList()
        return inflater.inflate(R.layout.fragment_products, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        addFab.setOnClickListener {
            findNavController().navigate(R.id.action_nav_products_to_addProductsFragment)
        }
        txtSearch.addTextChangedListener {
            productsViewModel.getProduct(txtSearch.text.toString())
        }
    }

    override fun getTitle(): String {
        return resources.getString(R.string.menu_products)
    }

    private fun setUpProductsList(){
        categoryViewModel.getCategories("").observe(this, Observer {categories->
            productsViewModel.getProduct("").observe(this, Observer {products->
                products.let {
                    val adapter = ProductListingAdapter( products, categories, requireActivity())
                    productRV.adapter = adapter
                    productRV.layoutManager = LinearLayoutManager(requireContext())
                }
            })
        })
    }
}

If you need more info, could you please comment. I will update the answer.



Solution 1:[1]

onDestroyView() get called when going forward to detail screen or another screen so obviously onCreateView() get called when user coming back from another screen. View is recreated, content is added, finally view is inflated. So automatically first visible item should be the zeroth index.

Most of the developers facing these kind of issues.

How to Handle: -> We need to fetch the content from ViewModel/repository only when adapter does not have any content. Below are code relevant snippet, hope this is helpful.

  1. Adapter creation

    private var adapter: MyAdapter? = null

  2. Initialize the adapter from onCreate() by passing relevant things

    adapter= MyAdapter(this)

  3. Mostly contents are fetching from onViewCreated() of fragment. Hence we need to fetch and add to adapter only when there is no data in adapter.

    if (adapter?.getItems()?.isEmpty() == true) fetchData() // could be io operation

it's worked for me.

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 Navas pk