Как достичь 0% ANR в Андроид-приложениях?
После года стараний, я наконец-то добился 0% ANR в респавне. Привожу краткий чеклист как я это сделал:
1. Добавьте логирование событий в Crashlytics. Crashlytics позволяет записывать любые логи в отдельное поле, чтобы видеть, что делал пользователь перед ANR. Библиотеки вроде FlowMVI позволяют делать это автоматически. Без этого вы не поймете, что привело к ANR, потому что их стактрейсы абсолютно бесполезные.
2. Полностью удалите SharedPreferences из вашего проекта. Особенно зашифрованные. Они являются причиной №1 ANR. Вместо этого используйте DataStore с Kotlin Serialization.
3. Поэкспериментируйте с обработкой событий UI в фоновом потоке, если вы имеете дело со сторонним SDK, вызывающим сбои. Это не решит ANR, а замаскирует его, уведя долгую операцию с мейна раньше.
4. Избегайте использования библиотек GMS в основном потоке. Они пишут свое дерьмо в префы. Создайте абстракции на основе корутин.
5. Проверьте использование Bitmap / drawable, растровые изображения при неправильном размещении (drawable-nodpi) могут привести к загрузке слишком больших изображений и анр.
6. Включите StrictMode и агрессивно устраняйте все операции ввода-вывода в основном потоке. Охереете, насколько их у вас много. Всегда держите StrictMode включенным.
7. Ищите утечки памяти: Никогда не используйте глобальные Coroutine Scopes. Добавляйте таймауты ко всем suspend-функциям с вводом-выводом. Добавляйте обработку ошибок. Используйте LeakCanary. Профилируйте использование памяти. Анализируйте аналитику из шага 1, чтобы найти действия пользователя, приводящие к ANR.
80% моих ANR были вызваны утечками памяти и происходили во время огромной GC-паузы.
8. Не верьте стектрейсам. Они вводят в заблуждение. 90% ANR вызваны вами. Я достиг 0.01% ANR после того, как серьезно отнесся к их поиску и перестал винить queue.NativePollOnce во всех своих проблемах. 0 ANR за последние 90 дней.
9. Избегайте загрузки файлов в память. Запретите использование File().readBytes(). Всегда используйте потоковую передачу для JSON, бинарных данных и файлов, рядов базы данных, шифруйте данные через Output/InputStream
10. Используйте Compose и избегайте тяжелых макетов. Некоторые устройства настолько плохи, что отрисовка UI вызывает ANR. Сделайте UI легким и загружайте его постепенно. Следите чтобы не было циклов рекомпозиций, их тяжело заметить.
11. Вызывайте goAsync() в броадкаст ресиверах, ставьте таймаут (обязательно!) и выполняйте работу в корутине. Это позволит в них избежать ANR из-за того, что броадкаст ресиверы часто выполняются системой под огромной нагрузкой (во время BOOT_COMPLETED сотни приложений гоняют броадкасты) и вам может прилететь анр просто потому что залагал телефон.
12. Избегайте байндеров сервисов вообще (bindservice()). Выгоднее будет отправлять события через application класс. Байндеры к сервисам всегда будут вызывать анр, хоть ты что сделай. Это нативный код который на сяоми топовых за свои деньги будет вступать в contention за системные вызовы на их древнем чипсете, а прилетать будет вам.
Post #744
1.5K
- 🔥 15
- 👍 9