Как оптимизировать главный поток UI
Что проверяют
Понимаете ли вы, сколько времени есть у главного потока на кадр и чем грозит его блокировка, и умеете ли находить виновника инструментами, а не угадывать. Следом обычно спрашивают про ANR и про то, как вы меряете плавность на реальных устройствах.
Как отвечать
Задайте рамку цифрами: при 60 Гц на кадр около 16 мс, при 120 Гц около 8 мс. Всё, что главный поток делает дольше, превращается в пропущенные кадры, а если он 5 секунд не отвечает на ввод, система показывает ANR.
Что убирать с главного потока:
- ввод-вывод и вычисления: корутины с
withContext(Dispatchers.IO)для сети, диска и базы,Dispatchers.Defaultдля парсинга и сортировки, запуск изviewModelScopeилиlifecycleScope. Room по умолчанию запрещает запросы с главного потока.AsyncTaskустарел ещё в API 30, предлагать его не стоит; - старт приложения: не инициализировать всё в
Application.onCreate, откладывать SDK ленивой инициализацией или через App Startup; - списки:
ListAdapterсDiffUtilсчитает разницу в фоне, в Compose уLazyColumnнужны стабильныеkey; - отрисовка: глубокая вложенность и overdraw во View, лишние рекомпозиции в Compose, которые снимают
remember,derivedStateOfи стабильные параметры; - мелкие ловушки:
SharedPreferences.commit()пишет синхронно (естьapply()и DataStore), большие картинки должны декодироваться в фоне через Coil или Glide.
Инструменты: StrictMode в debug-сборке ловит диск и сеть на главном потоке, System Trace в профайлере Android Studio и Perfetto показывают, что занимало кадр, Macrobenchmark меряет старт и прокрутку, Baseline Profiles ускоряют холодный старт, а JankStats и Android Vitals дают картину с устройств пользователей.
Где спотыкаются
Предлагают WorkManager для любой фоновой работы. Он для отложенных задач с гарантией выполнения, а не для данных, которые экран ждёт прямо сейчас.
Уносят всё в фон и забывают про обратный путь: трогать View из фонового потока нельзя, результат возвращается на Dispatchers.Main.
Оптимизируют наугад, без трассировки. Часто виновником оказывается не сеть, а синхронная инициализация SDK или тяжёлая рекомпозиция.