当前位置: 首页 > 科技观察

Android主线程崩溃和子线程崩溃的本质区别是什么?你是怎么处理的呢?

时间:2023-03-14 08:09:25 科技观察

问答环节Q:Android主线程崩溃和子线程崩溃的本质区别是什么?A:子线程崩溃就像普通的Java线程一样。通过setDefaultUncaughtExceptionHandler可以捕获ThreadGroup中子线程对应的异常进行后续处理(启动独立进程提醒用户并上报平台等,也可以通过策略下发忽略具体异常,就好像它没有发生。相同)。Android中主线程Crash和子线程Crash有一点区别。虽然本质可以通过setDefaultUncaughtExceptionHandler来捕获,但其实背后还有小技巧。Android主线程启动后,MainHandler的Looper.loop()维护了一个管道阻塞的生产者消费者无限循环,所有主线程代码都通过这个循环dispatch在MainLooper中执行,所以当主线程崩溃时,这个循环会被跳出,导致Looper无法继续执行其他Message,所以当主线程崩溃时,会有几种不同的表现。其中一种场景是Activity的onCreate中crash会导致界面变黑(注意这种crash不是anr,因为onCreate中抛出的异常导致后续代码无法执行,即,Activity生命周期框架代码无法继续,后续的Message无法正常派发,所以界面在出来之前是黑屏的),View点击事件响应中的crash可能不是黑屏(也可能是,取决于操作),但后续消息无法正常发送。扩展环节的问题:你对以上描述有什么看法?答:子线程的crash没什么好说的。由于主线程崩溃,Looper会退出,所以我们可以在主线程中启动一个带有try-catch的Looper.loop()来执行主线程任务,相当于这样,我们将Looper.loop替换掉了()在ActivityThreadmain中加上带try-catch的loop(),这样主线程崩溃后循环不会退出,代码可以继续执行,只有当崩溃发生的场景才可能失效。比如用户点击按钮设置了文案崩溃,点击按钮后可能没有任何反应;同时,点击按钮启动的Activity的onCreate方法有crash,会导致黑屏,所以这种crash需要区别对待(比如报异常)并弹框提醒并直接终止进程等)。下面是核心代码的简单实现(Activity生命周期处理比较粗糙,仅做demo)://应用启动并替换newHandler(getMainLooper()).post(newRunnable(){@Overridepublicvoidrun(){//每次跳转后继续循环一遍,保证loopwhile(true){try{Looper.loop();}catch(Throwablee){e.printStackTrace();//TODO手动报错给异常管理平台进行交互processingEtc.if(e.getMessage()!=null&&e.getMessage().startsWith("Unabletostartactivity")){//TODO来自Activity生命周期崩溃,kill进程android.os.Process.killProcess(android.os.Process.myPid());break;}}}}});当然,对于Activity生命周期方法中的crash黑屏,我们不仅可以判断栈日志方法,还可以实现hookActivityThread的mHmainHandler,并使用Host里面的Messagehandle函数我们的实现,然后try-catch捕获。如果发现异常,只需关闭对应的Activity或者杀掉app即可。其实这个方案网上有现成的开源库。你可以参考一下。本文转载自微信公众号“码农每日一问”,可通过以下二维码关注。转载本文请联系码农日报问题公众号。