Как работает Paging 3 библиотека? Какие основные компоненты и как интегрировать с Room?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Основы работы Paging 3
Paging 3 — это библиотека Android Jetpack для эффективной работы с большими списками данных. Она решает ключевые проблемы: экономия памяти (не загружая все данные сразу), снижение нагрузки на сеть/базу данных и плавный UX при пагинации. Библиотека работает на трех уровнях: DataSource (источник данных), PagingData (поток данных) и UI (отображение).
Основные компоненты
-
PagingSource — базовый источник данных, определяет логику загрузки "страниц" (page). Ключевые методы:
load(): загружает данные для конкретной страницыgetRefreshKey(): вычисляет ключ для восстановления состояния после refresh
-
RemoteMediator — компонент для гибридной пагинации (локальная БД + сетевой источник). Он координирует загрузку из сети и сохранение в Room, затем делегирует PagingSource для локальной выборки.
-
Pager — основной класс, который конфигурирует поток пагинации через
PagingConfig(размер страницы, prefetch расстояние, initial load size). -
PagingDataAdapter — адаптер для RecyclerView, который автоматически подгружает данные при скролле. Работает с DiffUtil для эффективных обновлений.
-
PagingData — тип данных, представляющий поток страниц, который можно наблюдать через Flow, LiveData или RxJava.
Интеграция Paging 3 с Room
Room напрямую поддерживает Paging 3 через возврат PagingSource из DAO методов. Это позволяет эффективно пагинировать результаты SQL запросов.
Пример реализации
1. Создание PagingSource в DAO:
@Dao
interface UserDao {
@Query("SELECT * FROM users ORDER BY name ASC")
fun getUsersPaged(): PagingSource<Int, User>
}
2. Конфигурация Pager в Repository или UseCase:
class UserRepository(private val userDao: UserDao) {
fun getUsersFlow(): Flow<PagingData<User>> {
return Pager(
config = PagingConfig(
pageSize = 20,
prefetchDistance = 10,
enablePlaceholders = false // или true если нужны placeholder'ы
),
pagingSourceFactory = { userDao.getUsersPaged() }
).flow
}
}
3. Подключение к UI через адаптер:
class UserAdapter : PagingDataAdapter<User, UserViewHolder>(USER_COMPARATOR) {
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
val user = getItem(position)
holder.bind(user)
}
companion object {
private val USER_COMPARATOR = object : DiffUtil.ItemCallback<User>() {
override fun areItemsTheSame(oldItem: User, newItem: User): Boolean =
oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: User, newItem: User): Boolean =
oldItem == newItem
}
}
}
4. Наблюдение данных в Activity/Fragment:
lifecycleScope.launch {
userRepository.getUsersFlow().collectLatest { pagingData ->
userAdapter.submitData(pagingData)
}
}
Ключевые особенности интеграции с Room
- Автоматическое управление ключами: Room использует
LIMITиOFFSETSQL параметры для пагинации, где ключом является номер страницы (Int). - Эффективные обновления: При изменении данных в таблице Room автоматически invalidates PagingSource, вызывая новый
load(). - Placeholders: Можно использовать
enablePlaceholders = true, но для этого запрос должен возвращать общее количество (COUNT) — Room не поддерживает это автоматически, нужно отдельная реализация. - Совместно с RemoteMediator: Для пагинации из сети с кэшированием в Room:
@ExperimentalPagingApi
class UserRemoteMediator(
private val localDb: AppDatabase,
private val api: UserApi
) : RemoteMediator<Int, User>() {
override suspend fun load(loadType: LoadType, state: PagingState<Int, User>): MediatorResult {
// Логика: загрузка из API, сохранение в Room, возвращение успеха/ошибки
}
}
// Использование в Pager
Pager(
config = PagingConfig(pageSize = 20),
remoteMediator = UserRemoteMediator(db, api),
pagingSourceFactory = { db.userDao().getUsersPaged() }
).flow
Преимущества такого подхода
- Единая абстракция: одинаковый API для локальной и сетевой пагинации.
- Оптимизация запросов: Room минимизирует запросы к БД через эффективные SQL пагинации.
- Reactive обновления: при изменении данных в БД через @Insert, @Delete etc., PagingData автоматически обновляет UI.
- Сочетание с Coroutines Flow: естественная интеграция с Kotlin корутинами и архитектурой ViewModel.
Таким образом, Paging 3 с Room создают мощный симбиоз для работы с большими данными, обеспечивая плавную пагинацию, эффективное использование ресурсов и чистую архитектуру с поддержкой как локальных, так и гибридных (сеть + БД) источников данных.