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