I am trying to use jetpack compose paging 3 library with start and limit, it loads the first items, but when I scroll trough the list it doesn't call the load method again.
I placed multiple logs, and I can see that the method is called just once, initially and then nothing happens after that. I really don't know what is wrong here. This is my code:
const val PAGE_SIZE = 30
class PhotosPagingSource (private val photosApi: PhotosApi) : PagingSource<Int, Photos>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Photos> {
return try {
val page = params.key ?: 0
val start = page * PAGE_SIZE
val limit = params.loadSize
val response = photosApi.getPhotos(start, limit)
val photos = PhotosMapper.mapPhotosDTO(response)
LoadResult.Page(
data = photos,
prevKey = if (page == 0) null else page - 1,
nextKey = if (response.isEmpty()) null else page + 1
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
override fun getRefreshKey(state: PagingState<Int, Photos>): Int? {
return state.anchorPosition
}
}
class PhotosRepositoryImpl @Inject constructor(
private val photosApi: PhotosApi,
): PhotosRepository {
override suspend fun getPhotos(): Flow<PagingData<Photos>> {
return Pager(config = PagingConfig(pageSize = 30, prefetchDistance = 3 )) {
PhotosPagingSource(photosApi)
}.flow
}
}
@HiltViewModel
class HomeViewModel @Inject constructor(
private val repository: PhotosRepository
) : ViewModel() {
init {
getPhotos()
}
private var _pagingFlow: MutableStateFlow<PagingData<Photos>> =
MutableStateFlow(value = PagingData.empty())
val pagingFlow: StateFlow<PagingData<Photos>> = _pagingFlow
private fun getPhotos() {
viewModelScope.launch(Dispatchers.IO) {
repository.getPhotos()
.distinctUntilChanged()
.cachedIn(viewModelScope)
.collect {
_pagingFlow.value = it
}
}
}
}
val lazyPagingItems = homeViewModel.pagingFlow.collectAsLazyPagingItems()
val state = lazyPagingItems.loadState
val listState = rememberLazyListState()
val pagingData = lazyPagingItems.itemSnapshotList
when {
state.refresh is LoadState.Loading && pagingData.size == 0 -> {
ShimmerHome()
}
state.refresh is LoadState.Loading && pagingData.size == 0 -> {
LoadingComposable()
}
state.refresh is LoadState.Error -> {
TODO()
}
state.append is LoadState.Loading -> {
LoadingComposable()
}
state.append is LoadState.Error -> {
TODO()
}
else -> {
LazyColumn(
modifier = Modifier,
state = listState,
contentPadding = PaddingValues(8.dp),
verticalArrangement = Arrangement.SpaceBetween,
horizontalAlignment = Alignment.CenterHorizontally,
content = {
items(items = pagingData) { pagingData ->
if (pagingData != null) {
PhotosCard(
photo = pagingData,
onCardClicked = {TODO() }
)
}
}
})
}
}
In jetpack don't use
itemSnapshotListand work only withlazyPagingItems. The thing is you have to useLazyPagingItems#get(index: Int)to get item and also notify paging data about that you are getting close to end of the page, from docs:With
itemSnapshotListpager doesn't know that you scrolled to bottom and need load another page.Updated code: