How to dynamically modify variables in PagingSource class, Paging Library 3.0

I have a livedata called selectedModuleTab which holds some variables like filters I need to pass those filters to the data source repository crmRepo in order to fetch data from server.

I just started to use Paging Library 3.0 and i can’t figure it out how to modify the PagingSource class every time my filters change.

I’ve tried to use Transformations but then i needed to create the Pager every time the filters change, this causes scroll position to be lost after returning to this view.

How can i modify the PageSource class every time a livedata changed (selectedModuleTab) ?

In my ViewModel I have this LiveData:

    val recordsList = Pager(PagingConfig(pageSize = 10),
    pagingSourceFactory = { RecordListPagingSource(crmRepo, selectedModuleTab.value) })
    .liveData
    .cachedIn(viewModelScope)

And this is my PageSource class:

    class RecordListPagingSource(private val crmRepo: CrmRepository, private val moduleTab: ModuleTab?) :
    PagingSource<Int, SmallRecordModel>() {
    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, SmallRecordModel> {
        return try {
            val page = params.key ?: 0
            LoadResult.Page(
                data = crmRepo.getRecordsListFromModuleSuspended(
                    ACCOUNT_MODULE,
                    (page * 10),
                    moduleTab?.tabFilters,
                    moduleTab?.tabLayout
                ),
                prevKey = page - 1,
                nextKey = page + 1
            )
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }
}

Answer

One way I’d do it is by making the load functionality outside of the PagingSource.

I don’t know how your structure is, but this is how I did my similiar implemenation.

A ViewModel for each Tab, to hold the logic for loading the pages, and also keep the state of the paging related to only the tab. Or one ViewModel where you pass the filters, if the API (or function) is the same. Then, change your Paging Source to take in a Suspended Function parameter, that knows tells the Paging Source how to load the data. Or, pass the Filter parameter into the Paging Source (assuming you went for the one-common ViewModel).

That way, each page knows what data needs to be loaded, and the Paging Source just loads the pages, while maintaining a common loading functionality.

From a personal experiance, go with the suspended function parameter, as it makes the PagingSource reusable independent of the page you are using, or even the kind of data.


P.S : If you’re new to developing apps, or using a library, don’t use the Alpha versions as sometimes they contain logic or features that are not completely finalized, as sometimes the functions or logic can change later.