美文网首页
android崩溃日志收集和处理

android崩溃日志收集和处理

作者: WhenMeet | 来源:发表于2018-01-02 17:28 被阅读268次

        android的崩溃很常见,我们往往通过日志收集避免下次更新的重复出错。

        android的崩溃发生后通常是由:

         Thread.UncaughtExceptionHandler  

         这个类进行处理的,那么我们要收集日志就要继承这个类进行一些处理即可。

        当我们继承后,有个方法必须要我们重写,那就是:

    @Override

    public void uncaughtException(Thread thread, Throwable throwable) {

    }

        当崩溃发生时,这个类就会调用这个方法进行处理,默认处理是手机卡住,然后几个键失灵,然后出现崩溃或者程序无响应对话框告诉你程序已经崩溃。

        但是现在我们要做处理了,我这里用到了三个类:

    1:ErrorCaught     继承刚才说的类,也就是Thread.UncaughtExceptionHandler

    2:ErrorHandle     看单词就知道,错误处理,那么当上面的错误发生后,一些操作是在这里面进行的,可能包含错误上传,保存这样的

    3:CrashInforMationDetail    这个看单词也容易知道意思,具体的错误信息,意思就是我们手机的错误日志就要从这里面拿

        好了,分配好任务,下面开始具体的操作

        按顺序来,先说第一个类:ErrorCaught, 继承了Thread.UncaughtExceptionHandler,那重点自然是看uncaughtException这个方法的具体操作,贴出代码:

    //异常崩溃发生时调用的方法,这里面开始我们想要的操作,包括日志的手机和上传等

    @Override

    public void uncaughtException(Thread thread, Throwable throwable) {

    errHandle.excute(thread, throwable);

    }

        出现了一个errHandle,不认得?不要紧,这就是我们上面说的第二个类,那么这里我们可以看到就是当崩溃发生时,我们调用了第二个类的一个方法,但是我们看到这里没有给errHandle初始化,那我们再看看第一个类:ErrorCaught的构造器

    private ErrorHandleerrHandle;

    //设置本程序的异常崩溃由此类处理

    public ErrorCaught(Application context){

    Thread.UncaughtExceptionHandler uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();

    errHandle =new ErrorHandle(context , uncaughtExceptionHandler);

    Thread.setDefaultUncaughtExceptionHandler(this);

    }

        很简单的一个构造器,就传了一个Context,但是有两行代码看不懂,中间的第二个类用构造器初始化大家应该看的懂吧,那么就说

    Thread.UncaughtExceptionHandler uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();

    Thread.setDefaultUncaughtExceptionHandler(this);

        这俩行的意思就是设置当前程序的崩溃类为这个类,也就是把原本系统捕捉崩溃的类的工作给代替了,这里我们是要写上的。

        那这第一个类的重点就很明显了,就是errHandle.excute(thread, throwable),我们去看看这个所谓的错误处理的类,到底是怎么处理崩溃这个事情的,打开这个类,我们看我们excute这个方法干了啥,

    //用来执行崩溃时具体的操作

    public void excute(Thread thread, Throwable throwable) {

    CrashInforMationDetail crashInforMationDetail = CrashInforMationDetail.produce(throwable, thread,context);

    crashInforMationDetail.writeToFile(crashFile);

    signOut(thread, throwable);

    }

        厉害了哈,这么快我们的第三个类就登场了,从代码中我们大概能看出,初始化了我们的第三个类,然后调用了writeToFile这个方法,很明显crashFile是一个文件,那这里的意思就是把错误的信息写到一个文件里面的,最后的signOut(thread, throwable);也容易看出来,退出程序,那思路就很明确了,当程序崩溃时,我们调用了我们捕捉崩溃的类,然后在捕捉崩溃的方法里面做了两件事,一:是保存错误信息,二:推出程序,和我们平时崩溃的不一样的就在通常程序崩溃了就没了,但是我们的不一样,就是做了日志保存处理,嗯,很智能。

    接着说第二个类吧,这个signOut方法是退出程序,我们看看代码:

    //强制退出软件

    public void signOut(Thread thread, Throwable throwable) {

    if (uncaughtExceptionHandler !=null) {

    uncaughtExceptionHandler.uncaughtException(thread, throwable);

    }else {

    android.os.Process.killProcess(android.os.Process.myPid());

    System.exit(1);

    }

    }

        又发现了我们第一个类的身影,它在这干啥,我们加了一个判断如果第一个类没有捕捉到崩溃异常处理,我们这里就把这个异常又交给系统去,如果获取本地崩溃的捕捉类,那就我们自己处理。还记得我们第一个类的构造器怎么写的么?里面有这俩行代码:

    Thread.UncaughtExceptionHandler uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();

    errHandle =new ErrorHandle(context , uncaughtExceptionHandler);

     看到没,我们第二个类获取的uncaughtExceptionHandler,是从第一个类来的,所以这里的处理就是没有一就没有二的意思。

    android.os.Process.killProcess(android.os.Process.myPid());

    System.exit(1);

        这俩行代码的意思就杀掉进程,退出程序。

        我们再看第一个类的构造器:

    public ErrorHandle(Application context, Thread.UncaughtExceptionHandler uncaughtExceptionHandler) {

    this.context = context;

    this.uncaughtExceptionHandler = uncaughtExceptionHandler;

    if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {

    File file =new File(Environment.getExternalStorageDirectory(),"crashCollection");

    if (!file.exists()) {

    file.mkdirs();//创建崩溃捕捉所在文件夹

            }

    crashFile =new File(file, getCrashFileName());

    if (!crashFile.exists()) {

    try {

    crashFile.createNewFile();//创建崩溃捕捉文件

                }catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    }

        意图大概很明确,是一个创建文件夹和文件的过程,那肯定就是创建崩溃日志的收集文件夹和文件。当然啦,我们要先检查有没有去权限等操作。看这个:getCrashFileName(),我们没找到是啥是吧,就是确定我们文件名的方法,给出代码:

    //获取崩溃文件名称,具体是年月日组成的文件名

    private String getCrashFileName() {

    StringBuilder stringBuilder =new StringBuilder();

    Calendar calendar = Calendar.getInstance();

    int year = calendar.get(Calendar.YEAR);

    int month = calendar.get(Calendar.MONTH);

    int date = calendar.get(Calendar.DATE);

    stringBuilder.append("crash_");

    stringBuilder.append(year +"-");

    stringBuilder.append(month +"-");

    stringBuilder.append(date);

    stringBuilder.append(".txt");

    return stringBuilder.toString();

    }

         下面说第三个类

    CrashInforMationDetail    用来采集错误信息的类,那么这里就是需要根据不同的需求来进行获取不同的信息,但是一般会包括俩种信息,

    1:手机设备的信息;2:崩溃产生的错误信息

    根据第一个错我这里写的有如下:

    //获取手机的一些设备参数

    public static String getSysytemInfor() {

    StringBuffer sb =new StringBuffer();

    sb.append("主板:" +Build.BOARD +"\n");

    sb.append("系统启动程序版本号:" +Build.BOOTLOADER +"\n");

    sb.append("系统定制商:" +Build.BRAND +"\n");

    sb.append("cpu指令集:" +Build.CPU_ABI +"\n");

    sb.append("cpu指令集2:" +Build.CPU_ABI2 +"\n");

    sb.append("设置参数:" +Build.DEVICE +"\n");

    sb.append("显示屏参数:" +Build.DISPLAY +"\n");

    sb.append("无线电固件版本:" +Build.getRadioVersion() +"\n");

    sb.append("硬件识别码:" +Build.FINGERPRINT +"\n");

    sb.append("硬件名称:" +Build.HARDWARE +"\n");

    sb.append("HOST:" +Build.HOST +"\n");

    sb.append("修订版本列表:" +Build.ID +"\n");

    sb.append("硬件制造商:" +Build.MANUFACTURER +"\n");

    sb.append("版本:" +Build.MODEL +"\n");

    sb.append("硬件序列号:" +Build.SERIAL +"\n");

    sb.append("手机制造商:" +Build.PRODUCT +"\n");

    sb.append("描述Build的标签:" +Build.TAGS +"\n");

    sb.append("TIME:" +Build.TIME +"\n");

    sb.append("builder类型:" +Build.TYPE +"\n");

    sb.append("USER:" +Build.USER +"\n");

    return sb.toString();

    }

        嗯,容易懂,大家可以挑着用,然后就是错误信息,这个错误信息我们是从Throwable里面取出来的:

    print.append(throwable.getMessage()).append("\n");

    StackTraceElement[] stackTrace = throwable.getStackTrace();

    try {

    for (int i =0; i < stackTrace.length; i++) {

    StackTraceElement stackTraceElement = stackTrace[i];

    String trace = stackTraceElement.toString();

    print.append(trace +"\n");

    crashInfor += trace +"\n";

    }

    }catch (Exception e) {

    e.printStackTrace();

    }

        只要我们有获取到了Throwable,这些信息全都可以拿到,包括错误的具体位置,那么我们看第三个类的构造器是什么样的,

    public static CrashInforMationDetail produce(Throwable throwable, Thread thread, Context context) {

    }

        里面有Throwable这个参数,也就是说第三类被调用的时候,我们就获取到了Throwable,那么这些错误信息我们就已经拿到了,然后再调用:

    public void writeToFile(File file) {

    PrintWriter printer =null;

    try {

    BufferedOutputStream out =new BufferedOutputStream(new FileOutputStream(file,true));

    printer =new PrintWriter(out);

    printer.println(crashInfor);

    printer.flush();

    }catch (IOException e) {

    e.printStackTrace();

    }finally {

    if (printer !=null) {

    printer.close();

    }

    }

    }

        把错误信息调到第二个类中进行存储成文件,下次程序重新进入的时候就可以上传这些错误文件了,我这里写的三类的怎么使用呢?大家只需要在自己的程序里面初始化第一个类就行了,也就是new一个:new ErrorCaught(this),就可以使用崩溃收集的功能了,不过要注意的就是存储权限要给到。

        好了,大概崩溃的发生和收集想必大家也是比较清晰了,我这里没有写上传的部分,因为上传的网络框架很多,大家可以根据自己的喜欢去挑选即可,重要的是知道这是怎么一个过程就行了,好了,今天的内容就说到这,咱们下次再见...

    代码点我:代码:android崩溃日志收集和处理

    相关文章

      网友评论

          本文标题:android崩溃日志收集和处理

          本文链接:https://www.haomeiwen.com/subject/tllqnxtx.html