为什么使用Throwable app不崩溃,使用Exception会崩溃
Throwable
是 Java/Kotlin 中异常体系的根类,Exception
只是它的子类之一,不能捕获所有错误。
✅ 异常体系结构(Java/Kotlin)
Throwable/ \Exception Error/ \RuntimeException IOException ...
🔥 为什么 Exception
捕不到 Error
?
Exception
只能捕获程序运行中**“预期内”的异常**,比如网络错误、空指针、数组越界等,但像以下这些属于 严重系统级错误,继承自 Error
,不会被 catch(Exception)
捕获:
UnsatisfiedLinkError
(找不到.so
文件)NoClassDefFoundError
(类加载失败)OutOfMemoryError
(内存溢出)StackOverflowError
(栈溢出)
所以你的代码:
try {// 可能抛出 UnsatisfiedLinkError
} catch (e: Exception) {// ❌ 捕获不到 Error
}
无法捕获 UnsatisfiedLinkError
,导致 APP 闪退。
✅ 改成这样就能兜底处理:
try {// 可能抛出 Error 或 Exception
} catch (t: Throwable) {// ✅ 能捕获 Error + ExceptionTimber.e(t, "异常发生:${t.message}")
}
这样,所有异常和错误你都能拿到,不会让 App 崩溃(除非 VM
已经无法继续运行)。
✅ 总结
捕获方式 | 能捕获 Exception | 能捕获 Error | 说明 |
---|---|---|---|
catch(Exception) | ✅ | ❌ | 无法捕获 UnsatisfiedLinkError |
catch(Throwable) | ✅ | ✅ | 能兜底处理所有异常与错误 |
二 有效捕获 Throwable
(包括 Exception
和系统级 Error
),防止 App 闪退:
✅ 1. 定义统一的 safeCall
方法
inline fun <T> safeCall(tag: String = "SafeCall",default: T,block: () -> T
): T {return try {block()} catch (t: Throwable) {Timber.tag(tag).e(t, "SafeCall caught an error: ${t.message}")default}
}
✅ 2. 使用示例(JNI 信号读取)
假设你要读取信号值 huFrtACSwReq
:
val result = safeCall(default = 0) {C38D_HU_Info4_100ms_Manager.getInstance().huFrtACSwReq.intValue()
}
Timber.d("Signal value is: $result")
无论 .so
是否丢失、类加载失败、JNI 断链,都会优雅兜底返回 0
,App 不崩溃。
✅ 3. 可选封装为扩展函数(更优雅)
inline fun <T> T.safeRun(tag: String = "SafeRun",default: T,block: T.() -> T
): T {return try {block()} catch (t: Throwable) {Timber.tag(tag).e(t, "SafeRun caught error: ${t.message}")default}
}
用法:
val result = C38D_HU_Info4_100ms_Manager.getInstance().safeRun(default = 0) {huFrtACSwReq.intValue()
}
☑️ 兼容性说明
- ✅ 支持捕获所有异常(
Throwable
) - ✅ 不依赖 Android API 版本
- ✅
Timber
可替换为Log.e
或你的日志系统 - ✅ 适合 JNI、CAN 信号、SDK 接口等不可控环境