Как выбрать между Paging 2 и Paging 3 и безопасно мигрировать

Выбор очевиден для большинства проектов: Paging 3 — современный, производительный и Kotlin‑ориентированный стандарт; миграция обычно занимает 1–2 дня и описана ниже с готовыми шагами.

Ключевые отличия Paging 2 и Paging 3

  • Архитектура:
    • Paging 2: DataSource (PageKeyed/Positional) с callback‑подходом (loadInitial, loadAfter).
    • Paging 3: единый PagingSource с suspend‑load, Pager и Flow. RemoteMediator для гибридного кэша (Room + сеть).
  • Асинхронность:
    • Paging 2 ориентирован на Java/Callback/RxJava2.
    • Paging 3 — нативно Coroutines/Flow; поддерживает RxJava3, Combine.
  • Кэш и синхронизация:
    • Paging 2: ручная интеграция с Room/Retrofit.
    • Paging 3: RemoteMediator упрощает инвалидацию, синхронизацию и кэширование.
  • Обработка состояний:
    • Paging 2: частично через PagedList и callback‑хуки.
    • Paging 3: LoadState, LoadStateAdapter, удобная обработка loading/error/refresh.
  • Производительность и стабильность:
    • Paging 3 обычно быстрее и экономнее по памяти в реальных сценариях (особенно при сетевых запросах и больших списках).

Paging 3 — рекомендованный Google вариант в 2026: лучшая интеграция с Kotlin, упрощённый кэш и предсказуемые LoadState.

Что выбрать в 2026 году

Выбирайте Paging 3, если:

  • Проект на Kotlin 1.6+ (особенно 1.9+) и вы используете Coroutines/Flow.
  • Нужны Room + сеть (RemoteMediator значительно упрощает).
  • Требуется масштабируемость и экономия памяти на больших списках.

Оставайтесь на Paging 2 только если:

  • У вас большой, стабильный Java‑проект без планов на Kotlin/Coroutines.
  • Вы не хотите тратить ресурсы на миграцию и фичи Paging 3 не нужны.

Если планируете долгосрочную поддержку и новые фичи (Compose, MPP), откладывать миграцию не рекомендуется — Paging 3 остаётся приоритетом.

Пошаговая миграция с Paging 2 на Paging 3

Оценочно: 1–2 дня для среднего проекта. Основные шаги:

  1. Обновите зависимости (пример для марта 2026):
implementation "androidx.paging:paging-runtime-ktx:3.3.2"
implementation "androidx.paging:paging-compose:3.3.2" // если Compose
  1. Переведите DataSource → PagingSource:
  • Замените PageKeyedDataSource/PositionalDataSource на класс, наследующий PagingSource<Key, Value>.
  • Реализуйте suspend fun load(params: LoadParams): LoadResult<Key, Value>.

Пример:

class MyPagingSource(private val repo: Repo) : PagingSource<Int, Item>() {
  override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Item> {
    return try {
      val page = params.key ?: 1
      val data = repo.fetch(page, params.loadSize)
      LoadResult.Page(data.items, prevKey = data.prev, nextKey = data.next)
    } catch (e: Exception) {
      LoadResult.Error(e)
    }
  }
}
  1. Создайте Pager и получайте Flow:
val flow: Flow<PagingData<Item>> = Pager(
  config = PagingConfig(pageSize = 20, enablePlaceholders = false),
  pagingSourceFactory = { MyPagingSource(repo) }
).flow
  1. Добавьте RemoteMediator при кэше через Room:
  • Реализуйте RemoteMediator<Key, Entity>, в load() синхронизируйте сеть и БД, используйте с Room PagingSource.
  1. Обновите UI:
  • Замените PagedListAdapter на PagingDataAdapter.
  • Подписка:
lifecycleScope.launch {
  viewModel.pagingFlow
    .cachedIn(viewModelScope) // обязательно
    .collectLatest { adapter.submitData(it) }
}
  • Добавьте LoadStateAdapter для footer/header, обработку refresh/loading/error.

Не забывайте cachedIn(viewModelScope) — без него данные не кэшируются корректно и возможны лишние запросы при пересоздании UI.

  1. Тестирование:
  • Проверяйте сценарии offline, empty state, retry.
  • Тестируйте производительность на больших списках и переключения конфигурации.

Частые ошибки

  • Забыт cachedIn — приводит к повторным загрузкам и утечкам.
  • Неправильная логика nextKey/prevKey — результаты могут зацикливаться.
  • Игнорирование LoadState — пользователи не увидят ошибки/индикацию загрузки.
  • Использование PagingSource как синглтона — PagingSource должен создаваться заново в pagingSourceFactory.

FAQ

  • Нужно ли мигрировать прямо сейчас?
    • Если проект активно развивается и использует Kotlin/Room/Retrofit — да. Для холодного Java‑проекта можно отложить, но планируйте миграцию в будущем.
  • Можно ли использовать Paging 3 с RecyclerView в Java?
    • Да, но вы потеряете часть синтаксического удобства Coroutines/Flow; API всё ещё совместимо с RecyclerView.
  • Стоит ли ждать Paging 4?
    • Paging 4 может добавить Compose MPP‑фичи, но Paging 3 актуален и поддерживается: мигрируйте сейчас, чтобы получить выгоды уже сегодня.

Если нужно, приложу конкретный пример миграции вашего DataSource → PagingSource или ревью кода миграции.