Hello! I have a problem with Paging v3 library on Android, here's what happens: When the app is open...
n

Nikita Khlebushkin

almost 4 years ago
Hello! I have a problem with Paging v3 library on Android, here's what happens: When the app is opened, the list is shown correctly and everything is great, but if I call
invalidate()
method of PagingSource, then it starts spamming
load
method of PagingSource (and doesn't even wait until the job is finished, cancels it and starts anew). This is the stacktrace:
2021-07-14 02:23:46.189 15215-15254/com.xlebnick.kitties.debug D/OkHttp: --> GET <https://myapi.com/v1/images/search?page=0&limit=24&order=ASC>
2021-07-14 02:23:46.189 15215-15254/com.xlebnick.kitties.debug D/OkHttp: x-api-key: 9b7e282d-2a67-4c7b-a9fd-3f3e4056e949
2021-07-14 02:23:46.189 15215-15254/com.xlebnick.kitties.debug D/OkHttp: --> END GET
2021-07-14 02:23:46.189 15215-15254/com.xlebnick.kitties.debug D/OkHttp: <-- HTTP FAILED: java.io.IOException: Canceled
2021-07-14 02:23:46.189 15215-15215/com.xlebnick.kitties.debug W/System.err: kotlinx.coroutines.JobCancellationException: StandaloneCoroutine was cancelled; job=StandaloneCoroutine{Cancelling}@6c3004
And this is my implementation:
class KittiesPagingSource(
    private val repository: Repository,
    var breedFilter: Breed? = null,
    var likedKitties: List<Like> = listOf()
) : PagingSource<Int, Kitty>() {


    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Kitty> {
        return try {
            // Start refresh at page 1 if undefined.
            val nextPage = params.key ?: 1

            val filters = if (breedFilter != null) listOf(breedFilter!!) else null
            var kitties: List<KittyRemoteModel> = listOf()
            try {
                kitties = repository.fetchKitties(nextPage, KITTIES_PAGE_SIZE, filters)
            } catch (e: Throwable) {
                e.printStackTrace()
            }

            val newKitties = kitties.map { kitty ->
                kitty.asKitty(likedKitties.any { it.imageId == kitty.id })
            }

            LoadResult.Page(
                data = newKitties,
                prevKey = if (nextPage == 1) null else nextPage - 1,
                nextKey = if (newKitties.isEmpty()) null else nextPage + 1
            )
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }

    override fun getRefreshKey(state: PagingState<Int, Kitty>): Int? {
        return state.anchorPosition?.let {
            if (it < state.config.initialLoadSize) {
                // if anchor position is less than initial loading count then download from the beginning
                0
            } else {
                // otherwise load a page around anchorPosition using initialLoadSize
                (it - state.config.initialLoadSize / 2).coerceAtLeast(0)
            }
        }
    }
}
private val kittiesPagingFactory = InvalidatingPagingSourceFactory {
        KittiesPagingSource(repository, breedFilter, likedKitties.value ?: listOf())
    }
    private val kittiesPager =
        Pager(PagingConfig(pageSize = 6), pagingSourceFactory = kittiesPagingFactory)
    val kitties: Flow<PagingData<Kitty>> = kittiesPager
        .flow
        .cachedIn(viewModelScope)
What am I doing wrong?