2

I have a recycler view that uses paging 3 inside a fragment. When an item on it is clicked, I need to show a bottom sheet with the exact same recycler view in a more elaborate way. I want to try and reuse the same recycler view adapter so that more API calls are not invoked unnecessarily (I already have all the required data from the recycler view in the parent fragment)

This is how I implement my parent fragment recycler view

        cardsRcView = binding.myCardsRcv.apply {
            // use this setting to improve performance if you know that changes
            // in content do not change the layout size of the RecyclerView
            setHasFixedSize(true)

            // use a linear layout manager
            layoutManager = CenterZoomLinearLayoutManager(context)

            // specify an viewAdapter (see also next example)
            adapter = cardsAdapter
        }
        cardsAdapter.apply {
            onClickCard = {
                val cardSheet = DetailsBottomSheet.newInstance(cardsAdapter,cardPos)
                cardSheet.show(childFragmentManager, "Card Details")
            }
        }

ViewModel:

fun fetchCards(
        orgId: String
    ): Flow<PagingData<UIModel>> {
        val pageSize = 5
        return Pager(
            config = PagingConfig(
                pageSize = pageSize,
                enablePlaceholders = false,
                initialLoadSize = pageSize
            ),
            pagingSourceFactory = {
                CardsPagingDataSource(
                    orgId = orgId,
                    getCardsUseCase = getCardsUseCase
                )
            }
        ).flow
}

And in the bottomsheet like this:

companion object {
        fun newInstance(
            cardsAdapter: CardsAdapter,
            cardPos: Int
        ): CardDetailsBottomSheet {
            val cardBottomSheet = CardDetailsBottomSheet()
            cardBottomSheet.cardsAdapter = cardsAdapter
            cardBottomSheet.cardPos = cardPos
            return cardBottomSheet
        }
    }

    private var cardsAdapter: CardsAdapter? = null
....
cardsRcView.apply {
            // use this setting to improve performance if you know that changes
            // in content do not change the layout size of the RecyclerView
            setHasFixedSize(true)

            // use a linear layout manager
            layoutManager = CenterZoomLinearLayoutManager(context)

            // specify an viewAdapter (see also next example)
            adapter = cardsAdapter
        }
        // This will affect my parent fragment adapter. I don't want it to.
        cardsAdapter?.apply {
            onClickCard = null
        }

How can I do this without making unnecessary API calls?

I have thought of getting the paging adapters.snapShot() and creating a new adapater inside the bottom sheet, but then how can I integrate the Paging to the recycler view inside the bottomsheet.

hushed_voice
  • 3,161
  • 3
  • 34
  • 66
  • Isn't it because you always create a new instance of Pager when calling fetchCards()? Maybe you could cache the Pagers for each orgId inside the ViewModel and reuse them in fetchCards()? – Mieczkoni Aug 01 '22 at 22:04
  • @Mieczkoni fetch card returns a Flow how can I cache it such that the paging will work in the bottomsheet as well? – hushed_voice Aug 02 '22 at 04:48

1 Answers1

1

Following the idea that it's beacuse of creating a new instance of Pager each time calling the fetchCards method. Here's an example for reusing the Pagers:

private val pagersMap = hashMapOf<String, Pager<String, UIModel>>()

fun fetchCards(orgId: String): Flow<PagingData<UIModel>> {
    val pager: Pager<String, UIModel> = pagersMap[orgId] ?: createPager(orgId)
    return pager.flow
}

private fun createPager(orgId: String): Pager<String, UIModel> {
    val pager = Pager(
        config = PagingConfig(
            pageSize = 5,
            enablePlaceholders = false,
            initialLoadSize = 5
        ),
        pagingSourceFactory = {
            CardsPagingDataSource(orgId)
        }
    )
    pagersMap[orgId] = pager
    return pager
}

But you'd have to test it with your data types etc.

Remember to use the same instance of ViewModel in both Fragments. I didn't see how you instantiate the ViewModel but you can do it by scoping it to either an Activity or parent Fargmenet (depends on your app structure) - more details here.

If you can't do it, maybe you should create some Repository and take the Pagers from there.

Mieczkoni
  • 505
  • 2
  • 8