1

Currently Paging library handles when to load the data automatically when a user scrolls down. But what if you want to give the user full authority for when they want the next page of data to be loaded i.e when button is clicked show next page of movies. How can you handle this in Paging library? See below how I've implemented the paging to load data as a user scrolls down

Here below this how I implemented the Paging to load next page when user scrolls down


class MoviesPagingDataSource(
    private val repo: MoviesRepository,
 ) : PagingSource<Int, Movies>() {

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

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Movies> {
        return try {
            val nextPageNumber = params.key ?: 0
            val response = repo.getMovies(page = nextPageNumber, size = 10)
            LoadResult.Page(
                data = response.content,
                prevKey = null,
                nextKey = if (response.content.isNotEmpty()) response.number + 1 else null
            )
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }
 }

This is how I emit the state in ViewModel for the UI to observe


@HiltViewModel
 class MoviesViewModel @Inject constructor(
   private val moviesRepository: MoviesRepository
): ViewModel {
   ....
   //emitting the data to the UI to observe

        val moviesPagingDataSource = Pager(PagingConfig(pageSize = 10)) {
        MoviesPagingDataSource(moviesRepository)
       }.flow.cachedIn(viewModelScope)
}

How I'm observing it in the UI


@Composable
fun MoviesList(viewModel: MoviesViewModel) {

    val moviesList = viewModel.moviesPagingDataSource.collectAsLazyPagingItems()

    LazyColumn {
        items(moviesList) { item ->
            item?.let { MoviesCard(movie = it) }
        }

        when (moviesList.loadState.append) {
            is LoadState.NotLoading -> Unit
            LoadState.Loading -> {
                item {
                    LoadingItem()
                }
            }
            is LoadState.Error -> {
                item {
                    ErrorItem(message = "Some error occurred")
                }
            }
        }

        when (moviesList.loadState.refresh) {
            is LoadState.NotLoading -> Unit
            LoadState.Loading -> {
                item {
                    Box(
                        modifier = Modifier.fillMaxSize(),
                        contentAlignment = Center
                    ) {
                        CircularProgressIndicator()
                    }
                }
            }
            is LoadState.Error -> TODO()
        }
    }
}

So currently I'm adding 1 to the previous page every time a user clicks the button to load more movies then saving this movies to the list state. Also making sure the current page is greater than or equal to total pages before loading more data and adding to the list state of previous loaded movies

1 Answers1

0

you can use Channel to block LoadResult returning from load, when user clicks the button, send an element to the Channel. here is the simple: https://github.com/sunchao0108/ComposePagingDemo

Jack
  • 1
  • 1
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 13 '23 at 14:55