ANR

Когда поток пользовательского интерфейса Android-приложения блокируется слишком долго, возникает ошибка «Приложение не отвечает» (ANR). Если приложение находится на переднем плане, система отображает пользователю диалоговое окно, как показано на рисунке 1. Диалоговое окно ANR предоставляет пользователю возможность принудительно завершить работу приложения.

Пользователю отображается диалоговое окно ANR.
Рисунок 1. Диалоговое окно ANR, отображаемое пользователю.

Проблемы с ANR возникают из-за того, что основной поток приложения, отвечающий за обновление пользовательского интерфейса, не может обрабатывать события ввода пользователя или отрисовывать изображение, что вызывает у пользователя раздражение. Более подробную информацию об основном потоке приложения см. в разделе «Обзор процессов и потоков» .

Событие ANR срабатывает для вашего приложения при возникновении одного из следующих условий:

  • Истекло время ожидания ответа на ввод: если ваше приложение не отреагировало на событие ввода (например, нажатие клавиши или касание экрана) в течение 5 секунд.
  • Выполнение службы: Если служба, объявленная вашим приложением, не может завершить выполнение Service.onCreate и Service.onStartCommand / Service.onBind в течение нескольких секунд.
  • Service.startForeground не вызывается: Если ваше приложение использует Context.startForegroundService для запуска новой службы на переднем плане, но служба не вызывает startForeground в течение 5 секунд.
  • Трансляция намерения: Если BroadcastReceiver не завершил выполнение в течение заданного промежутка времени. Если в приложении есть какая-либо активность на переднем плане, этот тайм-аут составляет 5 секунд.
  • JobScheduler interactions: If a JobService does not return from JobService.onStartJob or JobService.onStopJob within a few seconds, or if a user-initiated job starts and your app doesn't call JobService.setNotification within a few seconds after JobService.onStartJob was called. For apps targeting Android 13 and lower, the ANRs are silent and not reported to the app. For apps targeting Android 14 and higher, the ANRs are explicit and are reported to the app.

Если в вашем приложении возникают ошибки ANR (Anti-Resources — неработающие приложения), вы можете воспользоваться рекомендациями в этом документе для диагностики и устранения проблемы.

Выявите проблему

Если вы уже опубликовали свое приложение, вы можете использовать Android Vitals для просмотра информации об ошибках ANR для вашего приложения. Вы можете использовать другие инструменты для обнаружения ошибок ANR в реальных условиях, но обратите внимание, что инструменты сторонних разработчиков не могут сообщать об ошибках ANR на Android 10 и ниже, в отличие от Android Vitals.

Основные параметры Android

Android Vitals может помочь вам отслеживать и улучшать показатель ANR вашего приложения. Android Vitals измеряет несколько показателей ANR:

  • Показатель ANR: процент ваших ежедневно активных пользователей, у которых наблюдались какие-либо виды ANR.
  • Показатель количества ANR, воспринимаемых пользователями: процент ваших ежедневно активных пользователей, которые столкнулись хотя бы с одним случаем ANR, воспринимаемым пользователями . В настоящее время к категории ANR относятся только случаи типа Input dispatching timed out .
  • Показатель частоты множественных сбоев ANR: процент ваших ежедневно активных пользователей, у которых произошло как минимум два сбоя ANR.

Ежедневно активный пользователь — это уникальный пользователь, который использует ваше приложение в течение одного дня на одном устройстве, возможно, в течение нескольких сессий. Если пользователь использует ваше приложение на нескольких устройствах в течение одного дня, каждое устройство будет учитываться в общем количестве активных пользователей за этот день.

Показатель ANR (Australian No Reduction Rate), воспринимаемый пользователем, является ключевым фактором , влияющим на доступность вашего приложения в Google Play. Он важен, потому что учитываемые им ANR всегда происходят в тот момент, когда пользователь активно взаимодействует с приложением, вызывая наибольшие сбои.

В Play были определены два пороговых значения для нежелательного поведения по этому показателю:

  • Общий порог нежелательного поведения: как минимум 0,47% ежедневно активных пользователей сталкиваются с воспринимаемым пользователем нежелательным поведением (ANR) на всех моделях устройств.
  • Пороговое значение для некорректного поведения на устройстве: как минимум 8% ежедневных пользователей сталкиваются с воспринимаемым ими некорректным поведением (ANR) для одной модели устройства .

Если ваше приложение превышает общий порог нежелательного поведения, его, вероятно, будет сложнее найти на всех устройствах. Если ваше приложение превышает порог нежелательного поведения для отдельных устройств, его, вероятно, будет сложнее найти на этих устройствах, и в описании вашего приложения в магазине может появиться предупреждение.

Функция Android Vitals может оповестить вас через Play Console, если ваше приложение демонстрирует чрезмерное количество ошибок ANR.

Информацию о том, как Google Play собирает важные данные об Android, см. в документации Play Console .

Диагностика ANR

При диагностике ОНР следует обращать внимание на некоторые общие закономерности:

  • Приложение выполняет медленные операции ввода-вывода в основном потоке.
  • Приложение выполняет длительные вычисления в основном потоке.
  • Основной поток выполняет синхронный вызов функции связывания к другому процессу, и этот другой процесс долго возвращает результат.
  • Основной поток заблокирован в ожидании синхронизированной блокировки для длительной операции, которая выполняется в другом потоке.
  • Основной поток находится в тупиковой ситуации с другим потоком, либо в вашем процессе, либо из-за вызова связывателя. Основной поток не просто ожидает завершения длительной операции, а находится в тупиковой ситуации.

Следующие методы помогут вам определить причину ваших нарушений дыхания во сне.

HealthStats

HealthStats предоставляет метрики о состоянии приложения, фиксируя общее время работы пользователя и системы, время работы процессора, сетевые и радиоданные, время включения/выключения экрана и сигналы пробуждения. Это может помочь измерить общую загрузку процессора и разрядку батареи.

Отлаживать

Debug помогает проверять приложения Android во время разработки, включая трассировку и подсчет выделенной памяти для выявления рывков и задержек в работе приложений. Вы также можете использовать Debug для получения счетчиков памяти во время выполнения и в нативной памяти, а также метрик памяти, которые помогут определить объем памяти, занимаемый конкретным процессом.

ApplicationExitInfo

ApplicationExitInfo доступна в Android 11 (уровень API 30) и выше и предоставляет информацию о причине завершения работы приложения. Сюда входят ошибки ANR, нехватка памяти, сбои приложения, чрезмерное использование ЦП, прерывания со стороны пользователя, системные сбои и изменения разрешений во время выполнения.

Строгий режим

Использование StrictMode помогает обнаруживать случайные операции ввода-вывода в основном потоке во время разработки приложения. Вы можете использовать StrictMode на уровне приложения или активности.

Включить фоновые диалоги ANR

Android отображает диалоговые окна ANR для приложений, которые слишком долго обрабатывают широковещательное сообщение, только если в параметрах разработчика устройства включена опция «Показывать все ANR» . По этой причине фоновые диалоговые окна ANR не всегда отображаются пользователю, даже когда приложение испытывает проблемы с производительностью.

Узкие места рекомпозиции

Используйте профилировщик Android Studio и инспектор макетов , чтобы выявить узкие места, влияющие на производительность при создании композиции. Дополнительную информацию см. в разделе «Производительность Jetpack Compose» .

Загрузите файл трассировки.

Android сохраняет информацию о трассировке при возникновении ANR. В более старых версиях ОС на устройстве находится один файл /data/anr/traces.txt . В более новых версиях ОС существует несколько файлов /data/anr/anr_* . Вы можете получить доступ к трассировке ANR с устройства или эмулятора, используя Android Debug Bridge (adb) от имени root:

adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>

Вы можете получить отчет об ошибке с физического устройства, используя либо опцию «Получить отчет об ошибке» на устройстве, либо команду adb bugreport на вашей машине разработки. Для получения дополнительной информации см. раздел «Получение и чтение отчетов об ошибках» .

Устраните проблемы

После того, как вы определили проблему, вы можете использовать советы из этого раздела для устранения распространенных неполадок.

Медленная работа кода в основном потоке.

Определите места в вашем коде, где основной поток приложения занят более 5 секунд. Найдите подозрительные сценарии использования в вашем приложении и попробуйте воспроизвести ошибку ANR.

Распространенная проблема — это длительно выполняющаяся задача, находящаяся непосредственно в составном объекте:

@Composable
fun BadList(rawStrings: List<String>) {
    // Math or sorting inside the composable runs on EVERY recomposition pass!
    val heavilyProcessedList = rawStrings
        .filter { it.isNotBlank() }
        .map { it.uppercase().reversed() }
        .map { it.computationallyHeavyFunction() }
.sortedBy { it.length }
    LazyColumn { items(sortedList) { Text(it) } }
}

// Modern Compose-first fix
@Composable
fun GoodList(viewModel: MyViewModel = viewModel()) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()

    // UI simply renders state; no heavy processing allowed here
    LazyColumn { items(uiState.sortedData) { Text(it) } }
}

Ввод-вывод в основном потоке

Выполнение операций ввода-вывода в основном потоке является распространенной причиной замедления работы основного потока, что может привести к ошибкам ANR. В Compose разработчики часто случайно запускают операции чтения с диска (например, SharedPreferences или вызовы к базе данных) при попытке определить начальное состояние.

Выполняйте длительные операции ввода-вывода вне уровня пользовательского интерфейса. Используйте withContext(Dispatchers.IO) в ViewModel или, что еще лучше, используйте Repository на уровне данных .

Тупиковые ситуации

Взаимная блокировка возникает, когда поток переходит в состояние ожидания, поскольку необходимый ресурс удерживается другим потоком, который также ожидает ресурс, удерживаемый первым потоком. Если основной поток приложения находится в такой ситуации, высока вероятность возникновения ошибок ANR.

Взаимоблокировки — хорошо изученное явление в информатике, и существуют алгоритмы предотвращения взаимоблокировок, которые можно использовать для их избежания.

Для получения более подробной информации см. раздел «Взаимная блокировка и алгоритмы предотвращения взаимоблокировок» в Википедии.

При использовании Kotlin и Compose вы можете заменить примитивные блокировки неблокирующими сопрограммами-мьютексами ( Mutex.withLock ), чтобы предотвратить блокировку потоков, приостанавливая контекст выполнения вместо замораживания потока пользовательского интерфейса. Например:

import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

// Modern non-blocking concurrency state architecture
class SecureDataRepository {
    private val mutex = Mutex()

    suspend fun safeUIAccess() {
        // If locked, the main thread suspends seamlessly, preventing an ANR
        mutex.withLock {
            performSafeOperation()
        }
    }
}

Медленные приемники вещания

Приложения могут реагировать на широковещательные сообщения, такие как включение или выключение режима полета или изменение состояния подключения, с помощью широковещательных приемников. Ошибка ANR возникает, когда приложению требуется слишком много времени для обработки широковещательного сообщения.

Ангионервная регургитация возникает в следующих случаях:

  • Приёмник широковещательной рассылки не завершил выполнение своего метода onReceive в течение значительного промежутка времени.
  • Приемник широковещательной рассылки вызывает goAsync , но не может вызвать finish для объекта PendingResult .

Your app should only perform short operations in the onReceive method of a BroadcastReceiver . However, if your app requires more complex processing as a result of a broadcast message you should defer the task to a ViewModel (leveraging the power of Kotlin coroutines, scopes, and dispatchers) if the task is expected to take a few seconds at most, any type of state holder, or to WorkManager for tasks expected to take longer than a few seconds.

Игровая активность

Библиотека GameActivity позволила сократить количество ошибок ANR в тестах игр и приложений, написанных на C или C++. Заменив существующую нативную активность на GameActivity , вы сможете уменьшить блокировку потоков пользовательского интерфейса и предотвратить возникновение некоторых ошибок ANR.

Для получения дополнительной информации об ANR см. раздел «Обеспечение отзывчивости приложения» . Для получения дополнительной информации о потоках см. раздел «Повышение производительности за счет многопоточности» .

Дополнительные ресурсы

Просмотры контента

{% verbatim %} {% endverbatim %} {% verbatim %} {% endverbatim %}