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. PHP 生成、识别二维码及安装相关扩展/工具

    2018-02-20 00:30:26  更新:推荐新扩展(极力推荐) 这篇文章里用的两个二维码扩展都有些问题和麻烦:phpqrcode(生成二维码)的源码有点小 bug: 而 php-zbarcod ...

  2. linux系统时钟和硬件时钟不一致

    在做DB2 集群复制的时候要求两台主机时间相互一致. 但是在一台主机上系统时间和硬件时间相差12个小时左右:手动同步后,重启后又相差12个小时左右. 为什么会是这样的,先介绍下系统时钟和硬件时钟的区别 ...

  3. 转载: Android开源库V - Layout:淘宝、天猫都在用的UI框架,赶紧用起来吧!

    阿里的UI库... 分析的很精辟... http://blog.csdn.net/carson_ho/article/details/71077193

  4. spring boot jpa 多数据源配置

    在实际项目中往往会使用2个数据源,这个时候就需要做额外的配置了.下面的配置在2.0.1.RELEASE 测试通过 1.配置文件 配置两个数据源 spring.datasource.url=jdbc:m ...

  5. UrlRouteModule

    一.请求流程 当一个请求发往ASP.net MVC站点时的情景,IIS收到请求并将请求转到ASP.net,然后根据URL,或者更确切来说:被请求文件的扩展名.在IIS7 integrated模式下(默 ...

  6. python网络编程--RabbitMQ

    一:RabbitMQ介绍 RabbitMQ是AMPQ(高级消息协议队列)的标准实现.也就是说是一种消息队列. 二:RabbitMQ和线程进程queue区别 线程queue:不能跨进程,只能用于多个线程 ...

  7. supervisor的安装和配置

    1. 安装 yum install supervisor 2.配置 [unix_http_server] file=/tmp/supervisor.sock ;UNIX socket 文件,super ...

  8. CF3A 【Shortest path of the king】

    一句话题意:在8 * 8的棋盘上,输出用最少步数从起点走到终点的方案 数据很小,可以广搜无脑解决 定义数据结构体 struct pos{ int x,y,s; //x.y表示横纵坐标,s表示步数 ]; ...

  9. MinGW-MSYS Bundle Win32编译ffmpeg 生成DLL并加入X264模块

    组件资源站点 1)MinGW-MSYS Bundle http://sourceforge.net/projects/mingwbundle/files/ 2)yasm汇编器 http://yasm. ...

  10. jre安装配置!

    通常安装java开发环境都是jdk ,jre 一起安装,配置变量!分享一下只安装jre的配置! 去官网下载jre, 按提示安装成功! 和jdk配置一样 ,首先配置一下:JRE_HOME=C:\Prog ...