Search code examples
androidkotlinpaginationandroid-jetpackandroid-paging-3

Android Paging3 is not calling PageDataSource and always getting live data as null


I'm using Android Jetpack Paging3 library for pagination, i have followed the google code lab and some medium blogs for reference. I have implemented pagination as they suggested but it is not working,viewmodel is always returns null value. When i debug the application got to know that PageDataSource is not calling. I don't understand where is the issue i have followed as per the articles. Following is the code snippet of my project.

This code which i'm calling Pager in my RepositoryImpl class.

override suspend fun getSearchResult(searchKey: String): LiveData<PagingData<MyDataModel>> {
    return Pager(
        config = PagingConfig(NETWORK_PAGE_SIZE, enablePlaceholders = false),
        pagingSourceFactory = {
            MyPageDataSource(searchKey)
        }).liveData
}

This is my viewmodel class code

viewModelScope.launch{
        searchResult.value = Resource.loading(null)
        val response = repo.getSearchResult(searchKey)
        searchResult.value = Resource.success(response.value)
    }

This is MyPageDataSource class

 override fun getRefreshKey(state: PagingState<Int, MyDataModel>): Int? {
    return state.anchorPosition?.let { anchorPosition ->
        state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
            ?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
    }
}

override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MyDataModel> {
    // Start refresh at position 1 if undefined.
    val page = params.key ?: INITIAL_LOAD_SIZE
    val offset = params.loadSize
    return try {
        val response = searchRequest(searchQuery, page, offset) // its just api calling function which get result from API.
        val nextKey: Int?
        when (response) {
            is SearchResult.Success -> {
                nextKey = if (response.result.searchRes.isEmpty()) {
                    null
                } else {
                    // initial load size = 3 * NETWORK_PAGE_SIZE
                    // ensure we're not requesting duplicating items, at the 2nd request
                    page + (params.loadSize / NETWORK_PAGE_SIZE)
                }
                LoadResult.Page(
                    data = response.result.searchRes,
                    prevKey = if (page == INITIAL_LOAD_SIZE) null else page - 1,// Only paging forward.
                    // assume that if a full page is not loaded, that means the end of the data
                    nextKey = nextKey
                )
            }
            is SearchResult.NoResultFound -> {
                nextKey = null
                LoadResult.Page(
                    data = emptyList(),
                    prevKey = if (page == INITIAL_LOAD_SIZE) null else page - 1,// Only paging forward.
                    // assume that if a full page is not loaded, that means the end of the data
                    nextKey = nextKey
                )
            }

            is SearchResult.ServerError -> {
                val exception = Exception(response.message)
                LoadResult.Error(exception)
            }

        }

    } catch (e: Exception) {
        e.printStackTrace()
        LoadResult.Error(e)
    }
}

Solution

  • I tried different ways to workout the pagination, finally able to achieve the result by using function return type as LiveData. After that load function triggered everything worked out.

    Bellow is ViewModel code

     suspend fun getSearchResult(searchKey:String):LiveData<PagingData<MyDataModel>> =repo.getSearchResult(searchKey)
    

    in Fragment i have access it like this

     lifecycleScope.launch { viewmodel.getSearchResult(searchKey)..observe(viewLifecycleOwner) {
         result ->  //TODO}
    

    I have no idea why it didn't work out when i use the livedata variable to access. If there is any other solution please post it.