Рисунок 1. Пользователь увидел диалоговое окно с сообщением об ошибке ANR.
В этом документе описывается, как система Android определяет, что приложение не отвечает, и как обеспечить его работоспособность.
Даже если код написан идеально, приложение может работать медленно, зависать или долго обрабатывать входные данные. Если приложение не отвечает, когда оно открыто на экране, пользователь видит диалоговое окно с сообщением об ошибке ANR (см. рисунок 1). В диалоговом окне ANR пользователь может принудительно закрыть приложение. Если приложение работает в фоновом режиме, оно будет закрыто без уведомления. Чтобы диалоговые окна ANR появлялись как можно реже, необходимо обеспечить высокую скорость отклика приложения.
Триггеры ошибок ANR
Обычно система показывает ошибку ANR, если приложение не может ответить на действия пользователя в основном потоке (потоке UI), из-за чего система не может обработать входящие события ввода.
Например, ошибка ANR может возникнуть, если приложение выполняет блокирующую операцию I/O, такую как доступ к сети, в потоке UI. Другой пример – когда приложение тратит слишком много времени на создание сложной структуры в памяти или вычисление следующего хода в игре в потоке UI.
В Android задержка отклика приложения отслеживается системными сервисами ActivityManager и WindowManager. Android показывает диалоговое окно ANR, когда обнаруживает одно из следующих условий:
- Приложение не реагирует на ввод (например, нажатие клавиши или касание экрана) в течение пяти секунд.
BroadcastReceiverне завершает выполнение в течение 10–20 секунд для намерений на переднем плане. Подробнее о тайм-ауте широковещательного приемника…
Как избежать ошибок ANR
Ниже приведены общие рекомендации, которые помогут избежать ошибок ANR. Дополнительную информацию о диагностике и отладке ошибок ANR разных типов можно найти на других страницах этого раздела.
Основной поток должен быть всегда разблокирован. Используйте потоки стратегически.
Не выполняйте блокирующие или продолжительные операции в основном потоке приложения. Вместо этого используйте сопрограммы Kotlin, чтобы перенести работу на фоновые диспетчеры (например,
Dispatchers.IOилиDispatchers.Default). Используйте такие механизмы, какviewModelScope, чтобы безопасно запускать эти фоновые задачи, илиLaunchedEffect, чтобы запускать их в ответ на изменения состояния Compose.Постарайтесь свести к минимуму конфликты блокировок между основным и другими потоками.
Минимизируйте в основном потоке работу, не связанную с интерфейсом, например обработку широковещательных сообщений или запуск сервисов. Любой метод или функция, выполняемые в потоке UI, должны выполнять как можно меньше работы. В частности, действия должны выполнять как можно меньше операций для настройки в ключевых методах жизненного цикла, таких как
onCreateиonResume. Никогда не выполняйте операции ввода-вывода или тяжелые блокирующие вычисления непосредственно внутри composable-функции. Это блокирует поток пользовательского интерфейса во время композиции и рекомпозиции. Дополнительную информацию о доступных решениях для планирования работы в фоновом потоке и передачи данных обратно в интерфейс можно найти в обзоре фоновых задач.Будьте осторожны, когда используете пулы потоков в разных компонентах. Не используйте одни и те же потоки для потенциально длительных операций и задач, чувствительных ко времени, таких как широковещательный прием.
Обеспечьте быстрый запуск приложения. Минимизируйте медленные или блокирующие операции в коде запуска приложения, например методы, выполняемые во время настройки внедрения зависимостей (как в Hilt), или компоненты, инициализируемые с помощью библиотеки Jetpack App Startup. Вы можете дополнительно оптимизировать запуск приложения с помощью профилей базовой конфигурации, профилей запуска и R8.
Если вы используете
BroadcastReceiver, попробуйте запустить широковещательные приемники в неосновном потоке с помощьюContext.registerReceiver. Подробнее об ошибках ANR в BroadcastReceiver…- Если вы используете
goAsync, убедитесь, чтоPendingResult.finishвызывается до того, как истечет время ожидания ANR.
- Если вы используете
Ошибки ANR в BroadcastReceiver
Время выполнения BroadcastReceiver ограничено, поскольку широковещательные приемники предназначены для выполнения небольших дискретных объемов работы в фоновом режиме, например для сохранения настроек или регистрации Notification. Поэтому, как и в случае с другими вызовами методов в потоке UI, приложения должны избегать потенциально продолжительных операций или вычислений в широковещательном приемнике. Вместо того чтобы выполнять длительные задачи в потоке UI, выполняйте их в фоновом режиме. Подробнее о возможных решениях читайте в статье Обзор фоновых задач.
Ещё одна распространенная проблема с объектами BroadcastReceiver возникает, когда они выполняются слишком часто. Частое выполнение фоновых задач может уменьшить объем памяти, доступный другим приложениям. Подробную информацию о том, как эффективно включать и отключать объекты BroadcastReceiver, можно найти в статье Общие сведения о трансляциях.
Повышение скорости реагирования
Как правило, задержка в 100–200 мс уже воспринимается пользователями как медленная работа приложения. Вот несколько советов, которые помогут сделать приложение более отзывчивым:
Если приложение выполняет фоновую задачу в ответ на действия пользователя, покажите, что процесс идет, например с помощью
CircularProgressIndicatorилиLinearProgressIndicatorв интерфейсе.В играх вычисления для ходов должны выполняться в фоновой сопрограмме или рабочем потоке.
Если начальная настройка приложения занимает много времени, рекомендуем показывать заставку или как можно быстрее отрисовывать начальную композицию. Укажите, что идет загрузка, и заполните состояние интерфейса асинхронно. В любом случае мы рекомендуем каким-либо образом показывать, что процесс идет, чтобы пользователь не подумал, что приложение зависло.
Используйте инструменты для оценки производительности, такие как Perfetto и Профилировщик ЦП, чтобы определить, что замедляет работу приложения.