5.1 异常收集
一个健壮的App应该能搜集运行中所有的Crash信息,并将其发送到服务器以便程序员进行分析。
对于任何一款App而言,无论页面数量多少,我们也不可能在每个页面的每个方法都加上try…catch…语句来捕获Crash,而是需要一套统一的解决方案,将Crash一网打尽。
为此我们需要了解一个很重要的类:UncaughtExceptionHandler,用来处理未捕获的异常。未捕获异常指的是在程序中未使用try…catch…语句而抛出的异常。我们需要在App级别处理这些未捕获到的异常,算是最后一道关卡。
如果程序出现了未捕获异常,默认会弹出系统的强制关闭对话框。我们需要实现此接口,并在App中对其进行注册。这样当未捕获异常发生时,就可以做一些个性化的异常处理操作。
于是我们设计一个CrashHandler类,使之继承自UncaughtExceptionHandler,来定义我们自己的异常捕获逻辑,如下所示:
/** * UncaughtException处理类 ,当程序发生 Uncaught异常的时候 , * 由该类来接管程序 ,并记录发送错误报告 . * 需要在 Application中注册,为了要在程序启动器就监控整个程序。 */ public class CrashHandler implements UncaughtExceptionHandler { public static final String TAG = "CrashHandler"; public static final String APP_CACHE_PATH = Environment.getExternalStorageDirectory().getPath() + "/YoungHeart/crash/";
我们要实现CrashHandler的uncaughtException方法,详细的代码如下所示:
/** * 当 UncaughtException发生时会转入该函数来处理 */ @Override public void uncaughtException(Thread thread, Throwable ex) { if (!handleException(ex) && mDefaultHandler != null) { // 如果用户没有处理则让系统默认的异常处理器来处理 mDefaultHandler.uncaughtException(thread, ex); } else { try { Thread.sleep(3000); } catch (InterruptedException e) { Log.e(TAG, "error : ", e); } // 退出程序 android.os.Process.killProcess( android.os.Process.myPid()); System.exit(1); } }
这里只介绍其中最关键的方法,也就是handleException方法,这个方法做三件事情:
1)发错误日志到服务器。
2)给用户崩溃前的友好提示。
3)把错误日志记录到SD卡。
其代码如下所示:
/** * 自定义错误处理 ,收集错误信息 * 发送错误报告等操作均在此完成 * * @param ex * @return true:如果处理了该异常信息 ;否则返回 false. */ private boolean handleException(Throwable ex) { if (ex == null) { return false; } // 把 crash发送到服务器 sendCrashToServer(context, ex); // 使用 Toast来显示异常信息 new Thread() { @Override public void run() { Looper.prepare(); Toast.makeText(context, "很抱歉 ,程序出现异常 ,即将退出 .", Toast.LENGTH_SHORT).show(); Looper.loop(); } }.start(); // 保存日志文件 saveCrachInfoInFile(ex); return true; }
sendCrashToServer方法负责将捕获的异常发送到服务器,为此需要MobileAPI提供一个接口。表5-1中的信息都是很重要的,我们要事先准备这些数据。
表5-1 Crash数据表结构
有了上述机制,所有的异常就全都能被捕获到了。但并不是所有的异常都导致崩溃——我们希望尽可能留住用户,而不是App崩溃后重启。因为用户是不会重启打开App的,至少我不会。
有些异常是不严重的。比如说MobileAPI的数据不规范,该返回数值的却返回了字符串,不能为空的字段却返回了空值。这些数据中,有些数据仅仅是为了显示,显示与否无伤大雅,所以即使解析时出了问题抛出异常,也不应该崩溃。我们应该在相应的Activity,在具体解析数据的地方,加一层自定义的try…catch…语句,来捕获这些已知的异常。
需要注意的是,如果异常在Activity中就被捕获到了,就不会将其再交由Application级别的CrashHandler类去处理了。所以我们要在这个Activity的try…catch…语句中,手动把异常信息发送到服务器。在具体的Activity中,我们会将CrashType设置为0,而在CrashHandler中才会将CrashType设置为1。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论