Мне нужно отобразить довольно длинный список в LazyColumn, и для этого я использую Paging3. Локальная база данных комнаты — это SSOT, удаленный посредник загружает дополнительные данные в базу данных с помощью добавления. Моя проблема в том, что когда новая страница загружается в локальную базу данных и происходит недействительность, в пользовательском интерфейсе мой список подскакивает, и чем ниже я опускаюсь в список, тем больше этот скачок.
Это исторические данные, поэтому они сходят с сервера один раз, затем сидят в локальной базе данных и не изменяются, поэтому пользователь просматривает список один раз, позже он будет читать из локальной базы данных, и ему нужно будет загружать только самые новые элементы.
Я уже обнаружил, что проблема вызвана тем, что мои элементы имеют первичный ключ uuid, который не является возрастающим Int id, и у них есть параметр времени, на основе которого они находятся в порядке убывания. При вызове API следующая страница запрашивается на основе uuid последнего видимого элемента (и, конечно же, ограничения), поэтому nextKey может быть связан с элементом. Однако запрос помещения основан на смещении, поэтому чем глубже я нахожусь в списке, тем больше будет эта разница и скачок. Собственный PagingSource также может быть решением, но было бы хорошо сохранить SSOT. Есть ли какие-нибудь предложения о том, как остановить этот прыжок при прокрутке?
Код: Выделить всё
@Query("""
SELECT * FROM ITEM
ORDER BY TIME DESC
""")
fun getItemsPagingSource(): PagingSource
Код: Выделить всё
@OptIn(ExperimentalPagingApi::class)
fun getItemsPager(
scope: CoroutineScope
): Flow {
return Pager(
config = PagingConfig(
pageSize = PAGE_SIZE, //this is 60
prefetchDistance = PREFETCH_DISTANCE, // this is 20
enablePlaceholders = false,
),
pagingSourceFactory = {
dao.getItemsPagingSource()
},
remoteMediator = ItemRemoteMediator(
remoteDataSource,
dao,
PAGE_SIZE
)
).flow
.map { pagingData ->
pagingData
.map { entity ->
entity.toHistoryItem()
}
}
.cachedIn(scope)
.flowOn(coroutineDispatcher)
}
Код: Выделить всё
@OptIn(ExperimentalPagingApi::class)
class ItemsRemoteMediator(
private val remoteDataSource: ItemRemoteDataSource,
private val dao: ItemDao,
private val limit: Int
) : RemoteMediator() {
override suspend fun initialize(): InitializeAction {
return InitializeAction.SKIP_INITIAL_REFRESH
}
override suspend fun load(
loadType: LoadType,
state: PagingState
): MediatorResult {
return try {
val response = when (loadType) {
LoadType.REFRESH -> {
val oldestId = localDataSource.getOldestItemId()
when {
oldestId != null -> {
remoteDataSource.getHistories(
limit = limit,
lastVisibleItemId = oldestId,
)
}
else -> {
remoteDataSource.getHistories(
limit = limit,
)
}
}
}
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
LoadType.APPEND -> {
val lastItem = state.lastItemOrNull()
val lastItemDate = lastItem?.time // in utc
lastItem?.let {
remoteDataSource.getHistories(
lastVisibleItemId = it.id,
)
} ?: run {
remoteDataSource.getHistories(
limit = limit,
)
}
}
}
dao.saveItems(
historyItems = response.items,
)
MediatorResult.Success(
endOfPaginationReached = response.items.isEmpty()
)
} catch (e: Exception) {
MediatorResult.Error(e)
}
}
}
Подробнее здесь: https://stackoverflow.com/questions/799 ... e-mediator
Мобильная версия