Android App异常崩溃处理详解

异常崩溃是Android项目中一个棘手的问题,即使你做了很多的try - catch处理,也不能保证不崩溃,一旦崩溃就会出现下图的弹窗,xx应用就会停止运行这种体验对于用户来说是很差的,所以很明显我们做的app已经崩溃了。
Android App异常崩溃处理详解_第1张图片
像现在的企业应用,有的是在崩溃的时候直接启动一个统计异常的Activity,然后用户可以填写异常信息描述上报;还有就是直接闪退,不会出现如上图的弹窗,事实上用户 的体验觉会更糟,不知道它为什么闪退。

那异常可能随时发生,不能在每个代码块中去处理,肯定需要统一处理异常问题,这个就需要Java中的一个工具UncaughtExceptionHandler

1 UncaughtExceptionHandler

class AppCrashHandler : Thread.UncaughtExceptionHandler {
   
 
    override fun uncaughtException(t: Thread, e: Throwable) {
   
 
    }
}

UncaughtExceptionHandler是Java线程中的一个接口,它能够捕获到某个线程发生的异常。像try-catch是只能捕获主线程中的异常,子线程发送异常不会catch住,但是UncaughtExceptionHandler是可以捕获子线程中出现的异常的,当异常发生时,会回调uncaughtException方法,在这里可以做异常的上报。

1.1 替代Android异常机制

在文章的开头,我们看到Android中异常处理的机制就是闪退 + 弹窗,那么我们想自己处理异常并替换掉Android的处理方式,这个诉求其实Java中已经实现了,就是调用Thread的
setDefaultUncaughtExceptionHandler

class AppCrashHandler : Thread.UncaughtExceptionHandler {
   
 
    private var context: Context? = null
 
    fun init(context: Context) {
   
        this.context = context
        Thread.setDefaultUncaughtExceptionHandler(this)
    }
    override fun uncaughtException(t: Thread, e: Throwable) {
   
        Log.e(TAG, "thread name ${t.name} throw error ${e.message}")
 
    }
    companion object {
   
 
        private const val TAG = "AppCrashHandler"
 
        val instance: AppCrashHandler by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
   
            AppCrashHandler()
        }
    }
}

这样我们在app中初始化这个AppCrashHandler,看异常信息能不能捕获到。

class MainActivity : AppCompatActivity() {
   
 
    private lateinit var bigView: BigView
 
    override fun onCreate(savedInstanceState: Bundle?) {
   
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
//        bigView = findViewById(R.id.big_view)
        bigView.setImageUrl(assets.open("mybg.png"))
 
 
    }
}

这里我们没有初始化BigView,而是直接调用了它的一个方法,这里肯定是会报错的!运行之后,我们看到了一份日志信息

E/AppCrashHandler: thread name main throw error Unable to start activity ComponentInfo{
   
com.lay.image_process/com.lay.image_process.MainActivity
}: 
kotlin.UninitializedPropertyAccessException: 
lateinit property bigView has not been initialized

主线程抛出异常,原因就是bigView没有被初始化,这就说明异常是被捕获到了,而且我们会发现,app并没有闪退,这就是说明,我们已经替代了Android的异常处理方式。

1.2 可选择的异常处理

在第一部分中,我们捕获了异常,而应用程序没有不要闪回这真的是个好办法吗?事实上,我们可以尝试,返回和点击事件实际上并不 因为所有的进程都被终止了。

所以,捕获只是一部分,捕获后的处理也很重要,因为对于一些异常,我们不想自己处理它们,而是直接走系统的异常处理,其实这种风险就会降低,因为我们自己处理全部异常也不现实,也可能没有系统处理的好

defaultSystemExpHandler = Thread.getDefaultUncaughtExceptionHandler()

通过getDefaultUncaughtExceptionHandler()方法获取到的就是系统默认的异常处理对象,那么什么样的异常可以放给系统处理呢?在第一小节中,我们打印出的日志信息中发现uncaughtException捕获到的异常不是空的,那么有可能就是捕获到的异常是空的,那么就需要交给系统处理。

override fun uncaughtException(t: Thread, e: Throwable?) {
   
    Log.e(TAG, "thread name ${t.name} throw error ${e?.message}")
    if (e == null) {
   
        defaultSystemExpHandler?.uncaughtException(t, e)
    } else {
   
 
    }
}

如果捕获的异常不为空,那么我们需要自己处理异常,当异常发生时,app的进程已经到了崩溃的边缘,已经处于无响应状态,为什么 单击没有响应,是因为事件传递没有起作用,如果我们了解Android的事件处理机制,就应该明白,在ActivityThread的ma

你可能感兴趣的:(Android技术,android,kotlin,性能优化)