-
Notifications
You must be signed in to change notification settings - Fork 269
Open
Description
I decided to try Pager without the Room database. I use HashMap as the simplest database.
First I implemented PagingSource.
class MapPagingSource(
private val map: () -> Map<Int, List<Result>>
) : PagingSource<Int, Result>() {
override fun getRefreshKey(state: PagingState<Int, Result>): Int? {
println("TAG PagingSource anchorPosition ${state.anchorPosition}")
val anchor = state.anchorPosition ?: return null
val closest = state.closestPageToPosition(anchor) ?: return null
val page = closest.prevKey?.plus(1) ?: closest.nextKey?.minus(1)
return page
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Result> {
val map = map()
val position = (params.key ?: 0)
println("TAG PagingSource position = $position, size = ${map.size}")
return LoadResult.Page(
data = map[position] ?: emptyList(),
prevKey = if (position == 0) null else position - 1,
nextKey = if (position + 1 < map.size) position + 1 else null
)
}
}
After RemoteMediator
@OptIn(ExperimentalPagingApi::class)
class PokemonApiRemoteMediator(
private val map: () -> MutableMap<Int, List<Result>>,
private val append: () -> Unit
) : RemoteMediator<Int, Result>() {
private val ktor = Ktor()
override suspend fun initialize(): InitializeAction {
println("TAG RemoteMediator initialize")
return InitializeAction.LAUNCH_INITIAL_REFRESH
}
override suspend fun load(loadType: LoadType, state: PagingState<Int, Result>): MediatorResult {
val map = map()
println("TAG RemoteMediator $loadType, ${map.size}")
return try {
val latestPage = when (loadType) {
LoadType.REFRESH -> 0
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
LoadType.APPEND -> map.size
}
val subList = runCatching {
withContext(Dispatchers.IO) {
ktor.getData(state.config.pageSize, latestPage * state.config.pageSize)
}
}.getOrNull()
val data =
subList?.results ?: return MediatorResult.Success(endOfPaginationReached = true)
if (data.isEmpty()) return MediatorResult.Success(endOfPaginationReached = true)
if (loadType == LoadType.REFRESH) map.clear()
map[latestPage] = data
println("TAG RemoteMediator size ${map.size}")
if (loadType == LoadType.APPEND) append()
MediatorResult.Success(false)
} catch (e: Throwable) {
println("TAG RemoteMediator $e")
MediatorResult.Error(e)
}
}
}
And created a Pager in ViewModel
private val data: MutableMap<Int, List<Result>> = HashMap()
private var latestSource: MapPagingSource? = null
@OptIn(ExperimentalPagingApi::class)
private val _pager = Pager(
config = PagingConfig(10, enablePlaceholders = false),
remoteMediator = PokemonApiRemoteMediator(map = { data }) { },
pagingSourceFactory = {
println("TAG create source")
MapPagingSource { data }.also {
latestSource = it
} }
val adapter = Adapter()
init {
_pager.flow
.onEach {
println("TAG PagingData $it")
adapter.submitData(it)
}.launchIn(viewModelScope)
}
As I can see, the PagingData was created and sent to the adapter.
Then the PagingSource did not find the data and started the RemoteMediator.
After loading, the work stopped and the PagingSource did not start loading the data.
Of course, I can call "invalidate". But this will recreate the PagingSource, and will not add the data as if it were just making requests to the network from the PagingSource.

Metadata
Metadata
Assignees
Labels
No labels
