Как устроены item, item layout, item page и адаптер в RecyclerView
RecyclerView отображает элементы через Adapter + ViewHolder: onCreateViewHolder создаёт view, onBindViewHolder заполняет его данными, а Recycler хранит пул для переиспользования; item — модель, item layout — XML-разметка, item page — либо экран детали, либо порция данных при пагинации.
Коротко о терминах и что нужно помнить
- RecyclerView — контейнер, отвечающий за отрисовку, скролл и переиспользование view.
- Item — логическая модель (сообщение, товар и пр.).
- Item layout — XML для одного item (всё, что вёрстка показывает).
- ViewHolder — кэш ссылок на view + bind-метод.
- Adapter — мост между данными и RecyclerView: создаёт ViewHolder, привязывает данные, сообщает размер.
RecyclerView не знает и не хранит вашу бизнес-логику — он работает с количеством элементов и способами создания/заполнения view.
Жизненный цикл элемента: что реально происходит
- onCreateViewHolder(parent, viewType)
- Вы инфлейтите item layout и создаёте ViewHolder.
- Вызывается редко: примерно видимые элементы + запас для буфера.
- onBindViewHolder(holder, position)
- Берёте модель по position и полностью настраиваете view.
- Обязательно явно устанавливайте всё зависящее от данных (visibility, checked, тексты, изображения).
- Не выполняйте тяжёлые операции (сети, долгие вычисления).
Если не сбрасывать/устанавливать состояние в onBindViewHolder, оно «перетечёт» между позициями при переиспользовании.
- Переиспользование (recycler pool)
- Уходящий за экран ViewHolder попадает в пул и потом используется для другой позиции.
- Для очистки ресурсов используйте onViewRecycled(holder) (отмена загрузки изображений, сброс слушателей).
Item layout: как проектировать для производительности
- Минимизируйте вложенность — используйте ConstraintLayout или один уровень ViewGroup.
- Избегайте wrap_content там, где можно задать 0dp + constraints или фиксированный размер.
- Разделители рисуйте через ItemDecoration, а не в каждом item.
- Лёгкие фоны и отсутствие лишних теней повышают FPS.
Сделайте item layout как можно проще — прямое и самое эффективное улучшение плавности скролла.
Пример: ImageView 40dp + два TextView с 0dp ширины и constraint-ограничениями — вариант для лёгкого и предсказуемого layout.
Adapter, паттерны и оптимизация обновлений
- Храните логику отображения в ViewHolder.bind(item).
- Для обновлений используйте ListAdapter + DiffUtil или применяйте точечные notifyItemInserted/Removed/Changed.
- Не пересоздавайте адаптер при каждом обновлении — обновляйте список внутри адаптера.
- Для нескольких типов элементов реализуйте getItemViewType и отдельные ViewHolder'ы.
- Передавайте слушатели через конструктор адаптера; в колбэках проверяйте adapterPosition != NO_POSITION.
Оптимизации:
- setHasFixedSize(true) если размер RecyclerView не зависит от контента.
- Переиспользуйте один LayoutManager.
- Для картинок используйте Coil/Glide с отменой запросов в onViewRecycled.
Пагинация и что такое item page
- Item page в контексте списка — логическая порция данных (например, 20 элементов), загружаемая отдельно.
- При прокрутке к концу триггерите загрузку следующей страницы, добавляете элементы в адаптер и уведомляете его.
- Добавьте флаги isLoading/isLastPage и отдельный viewType для индикатора загрузки (footer).
Частые ошибки
- Пересоздание адаптера при каждом обновлении данных.
- Использование notifyDataSetChanged() вместо DiffUtil/точечных уведомлений.
- Игнорирование очистки состояний view при bind.
- Держать Context в полях адаптера/Holder без необходимости.
- Запуск тяжёлой логики в onBindViewHolder (сеть, парсинг).
FAQ
- Нужно ли отменять загрузку картинок? — Да: отменяйте в onViewRecycled или используйте библиотеку, которая делает это автоматически.
- Что использовать для сложных списков с разными item? — Sealed-классы для моделей + несколько viewType и ViewHolder.
- Как тестировать производительность? — Профилируйте GPU rendering, отслеживайте dropped frames и старайтесь упростить layout.
Если разделить ответственность: модели — в репозитории/ViewModel, отображение — в Adapter/ViewHolder, навигация — в Fragment/Activity, и применять DiffUtil + лёгкие item layout'ы, то RecyclerView работает предсказуемо и эффективно.