Snippets
Created by
John De la cruz
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
private const val STARTING_PAGE_INDEX = 1
@ExperimentalPagingApi
class PagingRemoteMediator(
private val userId: String,
private val service: NetworkData,
private val database: TimeSheetDatabase
) : RemoteMediator<Int, TimeSheet>() {
override suspend fun initialize(): InitializeAction {
return InitializeAction.LAUNCH_INITIAL_REFRESH
}
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, TimeSheet>
): MediatorResult {
val page : Int = when (loadType){
LoadType.REFRESH ->{
val remoteKeys = getRemoteKeyClosestToCurrentPosition(state)
remoteKeys?.nextKey?.minus(1) ?: STARTING_PAGE_INDEX
}
LoadType.PREPEND ->{
val remoteKeys = getRemoteKeyForFirstItem(state)
// If remoteKeys is null, that means the refresh result is not in the database yet.
// We can return Success with `endOfPaginationReached = false` because Paging
// will call this method again if RemoteKeys becomes non-null.
// If remoteKeys is NOT NULL but its prevKey is null, that means we've reached
// the end of pagination for prepend.
val prevKey = remoteKeys?.prevKey
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
prevKey
}
LoadType.APPEND -> {
val remoteKeys = getRemoteKeyForLastItem(state)
// If remoteKeys is null, that means the refresh result is not in the database yet.
// We can return Success with `endOfPaginationReached = false` because Paging
// will call this method again if RemoteKeys becomes non-null.
// If remoteKeys is NOT NULL but its prevKey is null, that means we've reached
// the end of pagination for append.
val nextKey = remoteKeys?.nextKey
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
nextKey
}
}
try {
val response = service.getTimeSheets(userId, page, state.config.pageSize)
val endOfPaginationReached = response.nextPage == null
database.withTransaction {
if (loadType == LoadType.REFRESH) {
database.remoteKeysDao().clearRemoteKeys()
database.timeSheetsDao()
}
val prevKey = if (page == STARTING_PAGE_INDEX) null else page - 1
val nextKey = if (endOfPaginationReached) null else response.nextPage
val keys = response.data.map {
RemoteKeys(timeSheetId = it.id, prevKey = prevKey, nextKey = nextKey)
}
database.remoteKeysDao().insertAll(keys)
database.timeSheetsDao().insertAll(response.data)
}
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
}catch (e : HttpAccess.NoNetworkException){
return MediatorResult.Error(e)
}catch (e: HttpException){
return MediatorResult.Error(e)
}catch (e: IOException){
return MediatorResult.Error(e)
}
}
private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, TimeSheet>): RemoteKeys? {
// Get the last page that was retrieved, that contained items.
// From that last page, get the last item
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let {
// Get the remote keys of the last item retrieved
database.remoteKeysDao().remoteKeysTimeSheetId(it.id)
}
}
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, TimeSheet>): RemoteKeys? {
// Get the first page that was retrieved, that contained items.
// From that first page, get the first item
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let {
// Get the remote keys of the first items retrieved
database.remoteKeysDao().remoteKeysTimeSheetId(it.id)
}
}
private suspend fun getRemoteKeyClosestToCurrentPosition(
state: PagingState<Int, TimeSheet>
): RemoteKeys? {
// The paging library is trying to load data after the anchor position
// Get the item closest to the anchor position
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.id?.let {
database.remoteKeysDao().remoteKeysTimeSheetId(it)
}
}
}
}
|
Comments (0)
You can clone a snippet to your computer for local editing. Learn more.