Java & Android未捕获异常处理机制

本文探讨了Java和Android中未捕获异常的处理机制。默认情况下,Java子线程的未捕获异常不会导致主进程退出,而Android则会因子线程异常导致App闪退。Android在系统层面自动输出Logcat中的异常堆栈信息。文章详细分析了Android的异常处理流程,包括异常预处理器和异常处理器的角色,以及如何自定义异常处理以避免质量监控三方库之间的冲突。
摘要由CSDN通过智能技术生成

一、背景

无论是Java还是Android项目,往往都会用到多线程。不管是主线程还是子线程,在运行过程中,都有可能出现未捕获异常。未捕获异常中含有详细的异常信息堆栈,可以很方便的去帮助我们排查问题。

默认情况下,异常信息堆栈都会在输出设备显示,同时,Java & Android为我们提供了未捕获异常的处理接口,使得我们可以去自定义异常的处理,甚至可以改变在异常处理流程上的具体走向,如常见的将异常信息写到本地日志文件,甚至上报服务端等。

在未捕获异常的处理机制上,总体上,Android基本沿用了Java的整套流程,同时,针对Android自身的特点,进行了一些特别的处理,使得在表现上与Java默认的流程会有一些差异。

二、未捕获异常处理流程

2.1 引子

我们先可以思考几个问题:

1,Java子线程中出现了未捕获的异常,是否会导致主进程退出?
2,Android子线程中出现了未捕获的异常,是否会导致App闪退?
3,Android项目中,当未作任何处理时,未捕获异常发生时,Logcat中的异常堆栈信息是如何输出的?
4,Android项目中,可能引入了多个质量监控的三方库,为何三方库之间,甚至与主工程之间都没有冲突?
5,Android中因未捕获异常导致闪退时,如何处理,从而可以将异常信息写到本地日志文件甚至上报服务端?
6,Java & Android对未捕获异常的处理流程有何异同?

先来看下第1个问题:

Java子线程中出现了未捕获的异常,是否会导致主进程退出?

可以做一个实验:

package com.corn.javalib;

public class MyClass {
   

    public static void main(String[] args) {
   
        System.out.println("thread name:" + Thread.currentThread().getName() + " begin...");

        Thread thread = new Thread(new MyRunnable());
        thread.start();

        try {
   
            Thread.currentThread().sleep(1000);
        } catch (Exception e) {
   
            e.printStackTrace();
        }

        System.out.println("thread name:" + Thread.currentThread().getName() + " end...");
    }

    static class MyRunnable implements Runnable {
   

        @Override
        public void run() {
   
            System.out.println("thread name:" + Thread.currentThread().getName() + " start run");

            errorMethod();

            System.out.println("thread name:" + Thread.currentThread().getName() + " end run");
        }//需要获取资料的朋友请加Q君样:290194256*
    }

    public static int errorMethod() {
   
        String name = null;

        return name.length();
    }

}

执行Java程序,最后输出结果为:

thread name:main begin...
thread name:Thread-0 start run
Exception in thread "Thread-0" java.lang.NullPointerException
	at com.corn.javalib.MyClass.errorMethod(MyClass.java:35)
	at com.corn.javalib.MyClass$MyRunnable.run(MyClass.java:26)
	at java.lang.Thread.run(Thread.java:748)
thread name:main end...

Process finished with exit code 0

我们发现,主线程中新起的子线程在运行时,出现了未捕获异常,但是,main主线程还是可以继续执行下去的,对整个进程而言,最终是Process finished with exit code 0,说明也没有异常终止。

因此,第一个问题的结果是:

Java子线程中出现了未捕获的异常,默认情况下不会导致主进程异常终止。

第2个问题:

Android子线程中出现了未捕获的异常,是否会导致App闪退?

同样的,新建Android工程后,模拟对应的场景,例如点击按钮,启动子线程,发现App直接闪退,AS Logcat中对应有如下日志输出:

2019-11-21 19:10:42.678 26259-26449/com.corn.crash I/System.out: thread name:Thread-2 start run
2019-11-21 19:10:42.679 26259-26449/com.corn.crash E/AndroidRuntime: FATAL EXCEPTION: Thread-2
    Process: com.corn.crash, PID: 26259
    java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
        at com.corn.crash.MainActivity.errorMethod(MainActivity.java:76)
        at com.corn.crash.MainActivity$MyRunnable.run(MainActivity.java:67)
        at java.lang.Thread.run(Thread.java:764)
2019-11-21 19:10:42.703 26259-26449/com.corn.crash I/Process: Sending signal. PID: 26259 SIG: 9

从日志信息上看,SIG: 9,意味着App进程被kill掉,日志信息堆栈中给出了具体的异常位置,于是,我们得出如下结论:

默认情况下,Android子线程中出现了未捕获的异常,在是会导致App闪退的,且有异常信息堆栈输出。

我们发现,基于Java基础上的Android,默认情况下,对于子线程中的未捕获异常,在进程是否异常退出方面,却有着相反的结果。

2.2 未捕获异常处理流程

接下来看下第3个问题:

Android项目中,当未作任何处理时,未捕获异常发生时,Logcat中的异常堆栈信息是如何输出的?

当Android项目中出现未捕获异常时,Logcat中默认会自动有异常堆栈信息输出,且信息输出的前缀为: E/AndroidRuntime: FATAL EXCEPTION:。我们很容易猜想到,这应该是系统层直接输出的,搜索framework源码,很快可以找到具体输出日志的位置:
在这里插入图片描述

在RuntimeInit.java中,找到了对应的异常日志输出位置,从代码注释上,我们找到了关键的KillApplicationHandler和UncaughtExceptionHandler类,先看下KillApplicationHandler类。
在这里插入图片描述

显然,KillApplicationHandler是未捕获异常发生时,默

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值