Оптимізація списків (RecyclerView/UITableView/ListView) мобільного додатку

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1735 послуг
Оптимізація списків (RecyclerView/UITableView/ListView) мобільного додатку
Середній
~2-3 дні
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    495

Оптимізація списків мобільної програми (RecyclerView/UITableView/ListView)

UITableView дергається при швидкому скролу — й майже завжди причина не в «повільному залізі», а в синхронній декодировці JPEG на main thread у cellForRowAt. Prefetch спрацьовує занадто пізно, ячійка вже запрошена, та поки зображення декодується — кадр пропущений. На iPhone SE 2nd gen з його скромною пам'яттю це відтворюється стабільно там, де на Pro не помічається взагалі.

Реальні причини торможень

Найчастіша історія на Android: RecyclerView з LinearLayoutManager та сотнями елементів, де в onBindViewHolder виконується Picasso.get().load(url).into(imageView) без явного placeholder та без відміни попереднього запиту через tag. При швидкому скролу запити накопичуються, старі не відміняються, UI-потік періодично блокується колбеками. Перехід на Glide з RequestManager привязаним до lifecycle та preload() в onScrollStateChanged розв'язує це без змін логіки.

На iOS аналогічна ситуація: SDWebImage без SDWebImageAvoidAutoSetImage застосовує зображення на main thread одразу після завантаження незалежно від видимості. Додаєш sd_setImageWithURL:placeholderImage:options:SDWebImageAvoidAutoSetImage та застосовуєш у completion лише якщо indexPath == self.tableView.indexPathForCell(cell) — та дергання зникає.

Друга по частоті проблема — важкі вычисленн висоти ячійки. UITableView.automaticDimension зручний, але при складному layout з кількома UILabel запускає повний systemLayoutSizeFitting на кожну видиму ячійку. Кеш висот через [IndexPath: CGFloat] та пересчет лише при зміні даних розв'язує проблему.

На Jetpack Compose LazyColumn без key {} не може коректно переіспользовувати composable при зміні даних — submitList з змінами елементів перерисовує всі видимі ячійки замість змінених.

Що робимо конкретно

Android RecyclerView:

  • setHasFixedSize(true) якщо розмір RecyclerView не змінюється при оновленні даних
  • setItemViewCacheSize(20) для збільшення offscreen кешу ячійок
  • RecycledViewPool.setMaxRecycledViews(type, count) при кількох RecyclerView з однаковим типом ячійок — шеринг пулу
  • AsyncListDiffer або ListAdapter з DiffUtil.ItemCallback — diff на фоновому потоці обов'язковий для будь-якого динамічного списку
  • Prefetch через LinearLayoutManager.setInitialPrefetchItemCount() для nested горизонтальних списків

iOS UITableView / UICollectionView:

  • prefetchDataSource — декодуємо та кешуємо дані до cellForRowAt
  • estimatedRowHeight з реальним значенням (не 44 для ячійок висотою 120) — неправильний estimatedRowHeight викликає стрибки при скролу
  • prepareForReuse() — обов'язкова відмова всіх async-операцій: imageLoadTask?.cancel()
  • Offscreen rendering ячійок через UIGraphicsImageRenderer для статичного контенту (аватари, іконки з накладанням)

Flutter LazyColumn (ListView.builder):

  • itemExtent — якщо всі елементи однієї висоти, указання фіксованого itemExtent убирає необхідність measure кожної ячійки
  • cacheExtent — збільшуємо до 500–1000 пікселів для preloading поза viewport
  • AutomaticKeepAliveClientMixin — зберігаємо стан ячійок при скролу назад

Кейс з вкладеними списками

Горизонтальний RecyclerView всередину вертикального — поширений паттерн для «Netflix-like» інтерфейсів. Типова помилка: кожен горизонтальний RecyclerView створює свій RecycledViewPool. При скролу вертикального списку горизонтальні ресайклятся разом з дочірними елементами, та при поверненні ячійки їхній стан (позиція скролу) втрачається.

Рішення: виносимо RecycledViewPool на рівень активності та передаємо в кожен горизонтальний RecyclerView через setRecycledViewPool(). Зберігаємо LinearLayoutManager.onSaveInstanceState() у ViewModel за ключем позиції. Результат — плавний скролл та збереження позиції при прокрутці вертикального списку.

Строки

Аудит та оптимізація одного проблемного списку — 2–4 дні. Системна робота з усіма списками у програмі — 1–2 тижні.