全局异常处理机制如同为App构建的"数字安全气囊",通过继承UncaughtExceptionHandler
建立多级防护体系:精准捕捉所有未被捕获的程序异常,自动完成关键信息采集、云端日志上传等诊断流程,并执行可控的优雅退出策略。该机制有效规避Android系统默认的强制关闭弹窗(Application Not Responding
),在保障用户体验连续性的同时,为开发者提供完整的异常全链路监控能力。
一、核心实现
1、自定义崩溃处理器(继承UncaughtExceptionHandler
)
kotlin
// 示例代码
class GlobalCrashHandler(private val context: Context) : Thread.UncaughtExceptionHandler {
// 原生的默认处理器(最后要交给它处理)
private val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
override fun uncaughtException(thread: Thread, ex: Throwable) {
// 1. 收集崩溃信息
val crashReport = CrashReport(
timestamp = System.currentTimeMillis(),
deviceInfo = collectDeviceInfo(),
stackTrace = ex.stackTraceToString(),
threadInfo = thread.toString()
)
// 2. 处理崩溃日志
saveCrashLocally(crashReport)
uploadCrashAsync(crashReport)
// 3. 主线程特殊处理
if (thread == Looper.getMainLooper().thread) {
handleUIThreadCrash()
}
// 4. 传递异常
defaultHandler?.uncaughtException(thread, ex) ?: run {
Process.killProcess(Process.myPid())
System.exit(10)
}
}
// 数据类用于封装崩溃信息
data class CrashReport(
val timestamp: Long,
val deviceInfo: Map<String, String>,
val stackTrace: String,
val threadInfo: String
)
private fun collectDeviceInfo(): Map<String, String> = mapOf(
"MANUFACTURER" to Build.MANUFACTURER,
"MODEL" to Build.MODEL,
"SDK_INT" to Build.VERSION.SDK_INT.toString(),
"APP_VERSION" to context.packageManager.getPackageInfoCompat().versionName
)
}
// 扩展函数获取PackageInfo
fun PackageManager.getPackageInfoCompat() = getPackageInfo(
"your.package.name",
PackageManager.GET_ACTIVITIES
)
2、Application中注册全局异常处理器
kotlin
// 示例代码
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
// 在应用初始化最后阶段注册
setupExceptionHandler()
}
private fun setupExceptionHandler() {
Thread.setDefaultUncaughtExceptionHandler(
GlobalCrashHandler(applicationContext)
)
}
}
3、AndroidManifest中指定Application类
xml
<application
android:name=".MyApp"
...>
</application>
二、注意事项
1、避免异常被「吃掉」
- 必须调用原有处理器的
uncaughtException()
- 不要直接
catch (Throwable t)
所有异常
2、第三方SDK的处理
- 三方SDK可能会覆盖默认处理器(如:Firebase Crashlytics),需在初始化 SDK 后设置自定义处理器。
3、不要屏蔽异常
kotlin
// 错误做法(会屏蔽默认行为)
override fun uncaughtException(thread: Thread, ex: Throwable) {
// 没有调用默认处理器
}
// 正确做法:始终调用super或默认处理器
4、ANR处理(结合WatchDog)
kotlin
// 示例代码
class ANRWatchDog : Thread() {
override fun run() {
while (!isInterrupted) {
val tick = AtomicLong(0)
Handler(Looper.getMainLooper()).post { tick.set(System.currentTimeMillis()) }
sleep(5000)
if (tick.get() < System.currentTimeMillis() - 5000) {
// 触发ANR处理
}
}
}
}
三、进阶技巧
1、本地存储
kotlin
// 示例代码
private fun saveCrashLocally(report: CrashReport) {
val logFile = File(context.filesDir, "crashes/${generateFileName()}")
logFile.parentFile?.mkdirs()
logFile.writeText(
buildString {
appendLine("====== CRASH REPORT ======")
appendLine("Time: ${formatTimestamp(report.timestamp)}")
report.deviceInfo.forEach { (k, v) -> appendLine("$k: $v") }
appendLine("\nStack Trace:")
append(report.stackTrace)
}
)
}
private fun generateFileName() = "crash_${SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())}.log"
2、异步上传
kotlin
// 示例代码
private fun uploadCrashAsync(report: CrashReport) {
CoroutineScope(Dispatchers.IO).launch {
try {
CrashUploader.upload(report)
} catch (e: Exception) {
// 记录上传失败
}
}
}
3、主线程崩溃特殊处理
kotlin
private fun handleUIThreadCrash() {
// 关闭所有Activity
(context as? Activity)?.run {
finishAffinity()
}
// 启动恢复Activity
val restartIntent = Intent(context, CrashRecoveryActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
context.startActivity(restartIntent)
// 延迟重启
Handler(Looper.getMainLooper()).postDelayed({
val launchIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)
context.startActivity(launchIntent)
}, 1500)
}
四、三方库推荐比对表
库名称 | 特点 | 适用场景 |
---|---|---|
Firebase Crashlytics | 实时报告,与Analytics集成 | 重度Google生态项目 |
Bugsnag | 支持跨平台,代码片段追踪 | 多平台统一监控 |
ACRA | 开源可定制,支持自建服务器 | 需要私有化部署的企业项目 |
Sentry | 性能监控+错误追踪一体化 | 全链路监控需求 |
五、最佳实践建议
1、分层处理策略
kotlin
// 不同层级处理异常
object ExceptionHandler {
// UI层捕获
fun handleUIException(ex: Exception) {
showErrorToast(ex)
logToAnalytics(ex)
}
// 数据层捕获
fun handleDataLayerException(ex: Exception) {
logToCrashlytics(ex)
recoverData()
}
}
2、关键路径保护
kotlin
fun safeLaunch(block: () -> Unit) {
try {
block()
} catch (ex: Exception) {
GlobalCrashHandler.uncaughtException(Thread.currentThread(), ex)
}
}
// 使用示例
fun fetchData() {
safeLaunch {
// 网络请求代码
}
}
3、崩溃分析工具
kotlin
// 使用AndroidX Startup初始化
class CrashAnalyticsInitializer : Initializer<Unit> {
override fun create(context: Context) {
setupCrashReporting()
}
private fun setupCrashReporting() {
if (!BuildConfig.DEBUG) {
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(true)
}
}
}
六、崩溃处理策略
发生崩溃 → 收集设备信息 → 保存本地日志 → 上传服务器 →
显示友好界面 → 尝试恢复 → 记录崩溃次数 → 达到阈值触发强制更新
扩展建议:
- 使用
ProcessPhoenix
库实现干净重启 - 结合
WorkManager
实现失败日志的自动重传 - 使用
Timber
进行增强日志记录 - 通过
Debug.getRuntimeStats()
获取更多运行时信息
此实现方案支持以下特性:
- 协程异步处理
- 扩展函数增强可读性
- 空安全类型系统
- 与Jetpack组件深度集成
- 支持多进程应用
可根据具体需求调整崩溃处理策略,建议在debug
构建中启用严格模式检测潜在问题。