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. linux下C获取系统时间的方法

    asctime(将时间和日期以字符串格式表示)  相关函数 time,ctime,gmtime,localtime  表头文件 #include  定义函数 char * asctime(const ...

  2. juery下拉刷新,ajax请求,div加载更多元素(一)

    ;//设置当前页数 var flag=true; //滑动加载 $(function(){ var winH = $(window).height(); //页面可视区域高度 $(window).sc ...

  3. 二、springcloud之熔断器hystrix

    一.背景 雪崩效应 在微服务架构中通常会有多个服务层调用,基础服务的故障可能会导致级联故障,进而造成整个系统不可用的情况,这种现象被称为服务雪崩效应.服务雪崩效应是一种因“服务提供者”的不可用导致“服 ...

  4. 在Eclipse使用Gradle

    1.Gradle安装 1.Grandle官网下载Gradle,地址:http://www.gradle.org/downloads 2.设置环境变量,需要设置如下2个环境变量 2.1添加GRADLE_ ...

  5. 蛮力法解决0_1背包问题新思路-——利用C语言位域类型

    废话不说了,直接上代码 #include<stdio.h> #include<math.h> #define N 5 //物品种类数目 #define CAPACITY 6 / ...

  6. 洛谷P2822组合数问题

    传送门啦 15分暴力,但看题解说暴力分有30分. 就是找到公式,然后套公式.. #include <iostream> #include <cstdio> #include & ...

  7. jersey 过滤器名称绑定的问题 NameBinding Provider

    查资料也不容易查,这个问题困扰了我两天. 当没有 @Provider 的时候 过滤器不会被执行.

  8. python中mock的使用

    什么是mock? mock在翻译过来有模拟的意思.这里要介绍的mock是辅助单元测试的一个模块.它允许您用模拟对象替换您的系统的部分,并对它们已使用的方式进行断言. 在Python2.x 中 mock ...

  9. HA下的Spark集群工作原理解密

    实验环境: zookeeper-3.4.6 Spark:1.6.0 简介: 本篇博客将从以下几点组织文章: 一:Spark 构建高可用HA架构 二:动手实战构建高可用HA 三:提交程序测试HA 一:S ...

  10. MyEclipse个性化设置

    1.修改项目文件默认编码 Note:myEclipse默认的编码是GBK, 也就是未设置编码格式的文件都默认使用GBK进行编码, 而更糟糕的是JSP.JavaScriptt默认编码竟然是ISO-885 ...