← Назад к вопросам
Как перехватить все runtime исключения в приложении
2.0 Middle🔥 162 комментариев
#Архитектура и паттерны#Многопоточность и асинхронность
Комментарии (2)
🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Глобальный перехват Runtime исключений в Android
Для перехвата всех необработанных исключений в Android-приложении используется механизм UncaughtExceptionHandler. Это особенно важно для:
- Логирования критических ошибок
- Корректного завершения работы приложения
- Отправки отчетов об ошибках на сервер
- Предоставления пользователю понятного сообщения об ошибке
Основной подход через Thread.setDefaultUncaughtExceptionHandler
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
// Логирование исключения
logException(throwable)
// Дополнительные действия
saveCrashReport(throwable)
notifyUserAboutCrash()
// Передача оригинальному обработчику для стандартного поведения
defaultHandler?.uncaughtException(thread, throwable)
}
}
private fun logException(throwable: Throwable) {
// Запись в файл или отправка на сервер
val logMessage = """
Time: ${System.currentTimeMillis()}
Thread: ${Thread.currentThread().name}
Exception: ${throwable.javaClass.name}
Message: ${throwable.message}
StackTrace:
${throwable.stackTrace.joinToString("\n")}
""".trimIndent()
// Пример записи в файл
File(filesDir, "crash_log.txt").appendText("$logMessage\n\n")
}
}
Расширенная реализация с сохранением состояния
class GlobalExceptionHandler(
private val originalHandler: Thread.UncaughtExceptionHandler?
) : Thread.UncaughtExceptionHandler {
override fun uncaughtException(thread: Thread, throwable: Throwable) {
try {
// 1. Сбор информации о системе
val deviceInfo = collectDeviceInfo()
// 2. Сохранение стека вызовов
val stackTrace = getStackTrace(throwable)
// 3. Сохранение в SharedPreferences для последующей отправки
saveCrashInfoToPrefs(deviceInfo, stackTrace)
// 4. Можно попытаться сохранить текущее состояние приложения
saveApplicationState()
} finally {
// Всегда вызываем оригинальный обработчик
originalHandler?.uncaughtException(thread, throwable)
}
}
private fun collectDeviceInfo(): Map<String, String> {
return mapOf(
"BRAND" to Build.BRAND,
"MODEL" to Build.MODEL,
"SDK_INT" to Build.VERSION.SDK_INT.toString(),
"APP_VERSION" to BuildConfig.VERSION_NAME,
"TIME" to SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
.format(Date())
)
}
}
Важные аспекты реализации
Ключевые моменты, которые необходимо учитывать:
- Порядок обработки: Всегда сохраняйте ссылку на оригинальный обработчик и вызывайте его в конце
- Время выполнения: Обработчик должен работать быстро, так как приложение находится в нестабильном состоянии
- Потокобезопасность: Убедитесь, что ваша реализация потокобезопасна
- Взаимодействие с UI: Не пытайтесь показывать диалоги или Toast в обработчике
Пример регистрации в разных точках приложения
// Регистрация в Application классе (рекомендуется)
class App : Application() {
companion object {
lateinit var instance: App
}
override fun onCreate() {
super.onCreate()
instance = this
setupExceptionHandler()
}
}
// Альтернативная регистрация в Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
setupActivityExceptionHandler()
}
}
private fun setupActivityExceptionHandler() {
val currentHandler = Thread.getDefaultUncaughtExceptionHandler()
Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
// Специфичная для Activity обработка
if (thread.name.contains("main")) {
saveCurrentActivityState()
}
currentHandler?.uncaughtException(thread, throwable)
}
}
}
Ограничения и предупреждения
Важные ограничения:
- Не все исключения можно перехватить: Некоторые системные ошибки (Native crashes, ANR) не проходят через этот механизм
- Производительность: Слишком сложная логика в обработчике может ухудшить процесс завершения приложения
- Совместимость: Разные версии Android могут иметь особенности в обработке исключений
- Повторные исключения: Обработчик сам может выбросить исключение, что приведет к немедленному краху
Альтернативные подходы
- Firebase Crashlytics: Автоматический сбор и анализ крэшей
- ACRA: Библиотека для отправки отчетов об ошибках
- Custom solutions: Собственные системы мониторинга ошибок
Рекомендация: Для продакшн-приложений лучше использовать комбинацию стандартного обработчика для базовой логики и специализированных сервисов (Crashlytics, Sentry) для полноценного мониторинга ошибок.