CrashHandler.java
UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告
package  com.amanda;
import  java.io.File;
import  java.io.FileOutputStream;
import  java.io.PrintWriter;
import  java.io.StringWriter;
import  java.io.Writer;
import  java.lang.Thread.UncaughtExceptionHandler;
import  java.lang.reflect.Field;
import  java.text.DateFormat;
import  java.text.SimpleDateFormat;
import  java.util.Date;
import  java.util.HashMap;
import  java.util.Map;
import  android.content.Context;
import  android.content.pm.PackageInfo;
import  android.content.pm.PackageManager;
import  android.content.pm.PackageManager.NameNotFoundException;
import  android.os.Build;
import  android.os.Environment;
import  android.os.Looper;
import  android.util.Log;
import  android.widget.Toast;
/**
 * UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告.
 * 
 *  @author  user
 * 
 */
public   class   CrashHandler   implements  UncaughtExceptionHandler {
    
     private   static   final  String  TAG  =  "CrashHandler" ;
     private   static   final  String  CRASH_FLOD_NAME  =  "crash" ;
    
     //系统默认的UncaughtException处理类 
     private  Thread.UncaughtExceptionHandler  mDefaultHandler ;
     //CrashHandler实例
     private   static   CrashHandler   INSTANCE  =  new   CrashHandler ();
     //程序的Context对象
     private  Context  mContext ;
     //用来存储设备信息和异常信息
     private  Map<String, String>  infos  =  new  HashMap<String, String>();
     //用于格式化日期,作为日志文件名的一部分
     private  DateFormat  formatter  =  new  SimpleDateFormat( "yyyyMMdd_kkmmss" );
     /** 保证只有一个CrashHandler实例 */
     private  CrashHandler() {
    }
     /** 获取CrashHandler实例 ,单例模式 */
     public   static   CrashHandler  getInstance() {
         return   INSTANCE ;
    }
     /**
     * 初始化
     * 
     *  @param  context
     */
     public   void  init(Context context) {
         mContext  = context;
         //获取系统默认的UncaughtException处理器
         mDefaultHandler  = Thread. getDefaultUncaughtExceptionHandler ();
         //设置该CrashHandler为程序的默认处理器
        Thread. setDefaultUncaughtExceptionHandler ( this );
    }
     /**
     * 当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);
        }
    }
     /**
     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
     * 
     *  @param  ex
     *  @return  true:如果处理了该异常信息;否则返回false.
     */
     private   boolean  handleException(Throwable ex) {
         if  (ex ==  null ) {
             return   false ;
        }
         //使用Toast来显示异常信息
         new  Thread() {
             @Override
             public   void  run() {
                Looper. prepare ();
                Toast. makeText ( mContext ,  "很抱歉,程序出现异常,即将退出." , Toast. LENGTH_LONG ).show();
                Looper. loop ();
            }
        }.start();
        
         //收集设备参数信息 
        collectDeviceInfo( mContext );
        
         //保存日志文件 
        saveCrashInfo2File(ex);
         return   true ;
    }
    
     /**
     * 收集设备参数信息
     *  @param  ctx
     */
     public   void  collectDeviceInfo(Context ctx) {
         try  {
            PackageManager pm = ctx.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager. GET_ACTIVITIES );
             if  (pi !=  null ) {
                 infos .put( "packageName" , pi. packageName );
                String versionName = pi. versionName  ==  null  ?  "null"  : pi. versionName ;
                String versionCode = pi. versionCode  +  "" ;                
                 infos .put( "versionName" , versionName);
                 infos .put( "versionCode" , versionCode);                
            }
        }  catch  (NameNotFoundException e) {
            Log. e ( TAG ,  "an error occured when collect package info" , e);
        }
        Field[] fields = Build. class .getDeclaredFields();
         for  (Field field : fields) {
             try  {
                field.setAccessible( true );
                 infos .put(field.getName(), field.get( null ).toString());
                Log. d ( TAG , field.getName() +  " : "  + field.get( null ));
            }  catch  (Exception e) {
                Log. e ( TAG ,  "an error occured when collect crash info" , e);
            }
        }
    }
     /**
     * 保存错误信息到文件中
     * 
     *  @param  ex
     *  @return     返回文件名称,便于将文件传送到服务器
     */
     private  String saveCrashInfo2File(Throwable ex) {
        
        StringBuffer sb =  new  StringBuffer();
         for  (Map.Entry<String, String> entry :  infos .entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append(key +  "="  + value +  "\n" );
        }
        
        Writer writer =  new  StringWriter();
        PrintWriter printWriter =  new  PrintWriter(writer);
        ex.printStackTrace(printWriter);
        Throwable cause = ex.getCause();
         while  (cause !=  null ) {
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }
        printWriter.close();
        String result = writer.toString();
        sb.append(result);
         try  {
             long  timestamp = System. currentTimeMillis ();
            String time =  formatter .format( new  Date());
            String fileName =  "crash_"  + time +  "_"  + timestamp +  ".log" ;
            String fileAbsPath =  "" ;
             if  (Environment. getExternalStorageState ().equals(Environment. MEDIA_MOUNTED ) && 
                    !Environment. getExternalStorageState ().equals(Environment. MEDIA_MOUNTED_READ_ONLY )) {
                fileAbsPath = Environment. getExternalStorageDirectory ().getPath()+File. separator + CRASH_FLOD_NAME +File. separator ;
            }
             else {
                fileAbsPath =  mContext .getFilesDir().getPath()+File. separator + CRASH_FLOD_NAME +File. separator ;
            }
            
            File dir =  new  File(fileAbsPath);
             if  (!dir.exists()) {
                dir.mkdirs();
            }
            
            FileOutputStream fos =  new  FileOutputStream(fileAbsPath + fileName);
            fos.write(sb.toString().getBytes());
            fos.close();
             return  fileName;
        }  catch  (Exception e) {
            Log. e ( TAG ,  "an error occured while writing file..." , e);
        }
         return   null ;
    }
}

 
CrashApplication.java
继承Application,实现全局crash报告记录
package  com.amanda;
import  android.app.Application;
public   class   CrashApplication   extends  Application {
     @Override
     public   void  onCreate() {
         super .onCreate();
        CrashHandler crashHandler = CrashHandler. getInstance ();
        crashHandler.init(getApplicationContext());
    }
}

 
AndroidManifest.xml
<? xml   version = "1.0"   encoding = "utf-8" ?>
< manifest   xmlns:android = "http://schemas.android.com/apk/res/android"
       package = "com.amanda"
       android:versionCode = "1"
       android:versionName = "1.0" >
    
     < uses-sdk  
         android:minSdkVersion = "15"
         android:targetSdkVersion = "15" />
     < uses-permission   android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />
     < application  
         android:name = ".CrashApplication"
         android:icon = "@drawable/icon"  
         android:label = "@string/app_name"
         android:allowBackup = "true" >
        
         < activity   android:name = ".MainActivity"
                   android:label = "@string/app_name"
                   android:theme = "@style/mytheme" >
             < intent-filter >
                 < action   android:name = "android.intent.action.MAIN"   />
                 < category   android:name = "android.intent.category.LAUNCHER"   />
             </ intent-filter >
         </ activity >

     </ application > </ manifest >

 
这样,就可以实现当出现UncaughtException时,将其相关信息保存到文件/sdcard/crash/xx.log或者/data/data/<package name>/file/crash/xx.log

保存全局Crash报告的更多相关文章

  1. 保存全局Crash报告&发送邮件

    上篇写到,将程序中没有处理到的crash信息保存到本地文件夹下.但是实际的情况是,你不可能总是将用户的设备拿过来.所以一般性的处理是,将crash reports发送到服务器或者邮箱.所以针对上篇的代 ...

  2. Android应用如何反馈Crash报告

    转自:http://www.cnblogs.com/draem0507/archive/2013/05/25/3099461.html 一.为什么要Crash crash可以理解成堕落,垮台.按照我们 ...

  3. ios如何生成crash报告

    #include <signal.h> #include <execinfo.h> void OnProcessExceptionHandler(int sigl) { do ...

  4. BFS(广度优先搜索遍历保存全局状态,华容道翻版做法)--08--DFS--蓝桥杯青蛙跳杯子

    题目描述 X星球的流行宠物是青蛙,一般有两种颜色:白色和黑色. X星球的居民喜欢把它们放在一排茶杯里,这样可以观察它们跳来跳去. 如下图,有一排杯子,左边的一个是空着的,右边的杯子,每个里边有一只青蛙 ...

  5. Breakpad Google的crash捕获、抓取开源库

    简介: Breadpad为google chrominum项目下用于处理dump的一套工具:内部采用跨平台方式实现捕获.生成.解析与平台无关的dump,便于统一处理:支持进程内与进程外捕获,当为进程外 ...

  6. iOS应用的crash日志的分析基础

        Outline如何获得crash日志如何解析crash日志如何分析crash日志     1. iOS策略相关     2. 常见错误标识     3. 代码bug 一.如何获得crash日志 ...

  7. Oracle AWR报告生成和性能分析

    目录 一.AWE报告生成步骤 1.1 工具选择 1.2 自动创建快照 1.3 手工创建快照 1.4 生成AWR报告 二.AWR报告分析 2.1 AWR之DB Time 2.2 AWR之load_pro ...

  8. 了解和分析iOS Crash

    WeTest 导读 北京时间凌晨一点,苹果一年一度的发布会如期而至.新机型的发布又会让适配相关的同学忙上一阵子啦,并且iOS Crash的问题始终伴随着移动开发者.本文将从三个阶段,由浅入深的介绍如何 ...

  9. 低于0.01%的极致Crash率是怎么做到的?

    WeTest 导读 看似系统Bug的Crash 99%都不是系统问题!本文将与你一起探索Crash分析的科学方法. 在移动互联网闯荡多年的iOS手机管家,经过不断迭代创新,已经涵盖了隐私(加密相册). ...

随机推荐

  1. Dream------scala--Tuple、Array、Map与文件操作

    1.Tuple(元组) 一般使用中,假设一个函数返回多个值,我们可以使用tuple接受这个(val (x,y) = myfunction) package com.wls.scala.hello /* ...

  2. Java NIO 之 Channel(通道)

    历史回顾: Java NIO 概览 Java NIO 之 Buffer(缓冲区) 其他高赞文章: 面试中关于Redis的问题看这篇就够了 一文轻松搞懂redis集群原理及搭建与使用 一 Channel ...

  3. 使用隐藏form表单下载文件,解决url方式下载,由于环境问题而限制url长度,满足不了所有的需求!

    一 对于某些环境导出是直接用wiondow.href=url直接导出下载,有些业务需求,如员工档案等字段比较多的时候,全选导出就会引发异常,由于Nginx转发长度限制的问题, 如果运维不愿意改变环境, ...

  4. 自动化测试Robotium获取当前页面的activity,用于判断是否进入这个页面

    一.启动app 二.进入命令行窗口输入 adb shell “dumpsys activity activities | grep mFocusedActivity” 三.断言方法 assertTru ...

  5. 数据科学实战手册(R+Python)书中引用资料网址

    本文会持续将<数据科学实战手册(R+Python)>一书中的附带参考资料网址手打出来, 方便访问. 由于书中的参考资料网址太多, 这个文档将可能花费一段时间才能完成. 第一章 P7  Rs ...

  6. Codefroces 628B New Skateboard(数位+思维)

    题目链接:http://codeforces.com/contest/628/problem/B 题目大意:给你一段数字串s(1?≤?|s|?≤?3·10^5),求该字符串有多少子串是4的倍数.解题思 ...

  7. HDU 3861 The King’s Problem(强连通分量+最小路径覆盖)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 题目大意: 在csdn王国里面, 国王有一个新的问题. 这里有N个城市M条单行路,为了让他的王国 ...

  8. afl入门学习

    一个简单的示例 安装afl wget http://lcamtuf.coredump.cx/afl.tgz tar xfz afl.tgz cd afl-xxx sudo make install 用 ...

  9. Spring Boot使用JavaMailSender发送邮件

    http://www.cnblogs.com/wxc-xiaohuang/p/9532631.html https://blog.csdn.net/icannotdebug/article/detai ...

  10. 同时装有py2 和3,运行scrapy如何区分

    1未区分环境 python2 -m scrapy startproject xxx python3 -m scrapy startproject xxx 当然,执行的时候也是 python2 -m s ...