[崩溃] Android应用永不崩溃的秘诀

App的崩溃率,是性能的一个重要的衡量指标。做过客户端开发的朋友,肯定与线上各种各样的崩溃问题打过交道。我们有没有什么办法能提高程序的稳定性、降低崩溃率,甚至做到永不崩溃呢?对于Java崩溃,答案是肯定的。

根据上一篇文章Java和Android崩溃捕获机制,我们知道了Android崩溃捕获的机制。简单总结就是:所有线程的崩溃,最后都会回调到UncaughtExceptionHandler,调用uncaughtException方法进行处理。

Android应用程序在发生未捕获崩溃时,会自动退出进程的原因,是因为Android系统在启动的时候,注册了一个KillerAppExceptionHandler的全局 defaultExceptionHandler。所有线程的崩溃都会被这个Handler处理。而这个Handler的处理逻辑非常简单,就是先打印日志,然后退出进程。所以,在Android系统上运行的App,发生未捕获异常的时候,会自动退出进程。

这篇文章,我们来看看如何实现程序的永不崩溃。

基本原理

基本原理其实很简单,我们可以通过设置自己的defaultExceptionHandler,来替代系统默认的KillerAppExceptionHandler。然后在我们的Handler里面,让进程不崩溃,只做一些上报的工作,就可以实现App永不崩溃。

但是,对于主线程,我们不能直接这样处理。因为主线程是有个Looper,如果程序发生未捕获异常,主线程会被退出,这个时候Looper也就无法继续执行了,会造成ANR,所以主线程需要单独做处理,让Lopper一直不退出。

下面我们会对子线程和主线程两种情况分别进行讨论。

子线程

子线程的情况比较简单,当出现未捕获异常时,直接让线程退出即可。

sUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
 // 默认的异常拦截处理器,主线程的异常会用try-catch,不会抛出,所以下面的代码拦截到的都是子线程的异常
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
          if(catchException){
              // 可以在这里做一些上报
          }else{
              // 调用原始的uncaughtExceptionHandler进行处理
              sUncaughtExceptionHandler.uncaughtException();
          }
    }
});

主线程

由于主线程需要一直运行,所以不能直接用抛出异常,uncaughtExceptionHandler拦截处理的方式,必须让主线程的循环继续执行下去。

 new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        while (true) {
            try {
                //主线程的异常会从这里抛出
                Looper.loop();
            } catch (Throwable e) {
                // 可以在这里做一些上报
            }
        }
    }
});

原理相当于我们在Looper的死循环外面又套了一层死循环,这样当内存的死循环因为抛出异常退出的时候,外层的死循环还能继续执行。

大致的运行流程:

  • 往主线程的MessageQueue中post一个Runnable,当主线程执行到该Runnable时,会进入我们的while死循环。
  • 在这个循环里面,调用了Looper.loop()方法,使得主线程可以循环起来,读queue中的Message并执行,也就是主线程不会被阻塞。
  • 如果主线程在Message执行中抛出异常,因为我们加了try-catch捕获,所以不会往外抛出异常,而会直接走catch的逻辑。
  • 走完catch之后,又再次进入while循环中。

可能引起的ANR问题

如果在主线程抛出异常的时候,拦截异常,但是又不启动主线程的Looper,就会造成ANR。

比如如下代码,就可能造成ANR的问题:

 Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(final Thread t, Throwable e) {
            return;
        }
 });

所以在使用的UncaughtExceptionHandler的时候,一定要记得重启主线程的Looper,否则即使不崩溃,程序也无法继续运行。

几个问题

  1. 主线程的方案,相当于在所有的方法执行外层都加了try-catch,会不会影响性能?
    答:性能损耗可以忽略,从反编译出的指令发现,加了try-catch块的代码跟没有加的代码运行时的指令是完全一直的。如果程序运行过程中,不产生异常的话,try-catch几乎不会对运行产生任何影响。只有在发生异常的时候,JVM会追溯宜昌站,这部分耗时就比较高了。

  2. 崩溃后,之后的业务逻辑还能继续执行吗?
    答:不可以,子线程如果遇到崩溃就会直接退出,主线程遇到崩溃,当前的Message的执行也会结束。这个方案只能保证不崩溃,无法保证不会有业务逻辑的问题,所以可以在使用的时候增加一些判断条件,比如,遇到特定的已知的崩溃才进行捕获。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容