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. Python——列表的操作

    列表的操作:详细+易出错假设有两个列表:    list1 = [1,2,3]    list2 = ['a','b','c']列表的操作: 1.list.append()    append只接受一 ...

  2. 查看linux系统的信息

    #!/bin/sh ################################################## #function:get host's information #Autho ...

  3. wamp中mysql安装时能启动,重启后无法启动的解决办法

    第一次安装wamp之后,所有服务可以正常使用,但是重启之后wamp的图标就变成黄色的了,重装了也这样 查看一下错误日志: 日志显示的错误是这样的: 日志提示可能是3306端口被占用的错误,那来看一下是 ...

  4. Linux机器如何在公司内网配置代理

    一.通过上网认证 必须在图形界面下使用浏览器(如Firefox)完成上网认证过程. 请先确保本机已经可以正常访问公司内部网络. Firefox上配置代理: 1)打开Firefox首选项,[高级]-[网 ...

  5. ip_local_deliver && ip_local_deliver_finish

    当ip包收上来,查路由,发现是发往本地的数据包时,会调用ip_local_deliver函数: ip_local_deliver中对ip分片进行重组,经过LOCAL_IN钩子点,然后调用ip_loca ...

  6. hibernate的枚举注解@Enumerated

    @Enumerated(value=EnumType.ORDINAL)采用枚举类型的序号值与数据库进行交互, 此时数据库的数据类型需要是数值类型,例如在实际操作中 CatTest ct = new C ...

  7. linux java配置

    1.java配置 配置环境变量在/etc/profile下增加# set Java environmentJAVA_HOME=/usr/share/jdk1.6.0_43PATH=$JAVA_HOME ...

  8. 追MM与设计模式

    1.FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说“来四个鸡翅”就行了.麦当劳和肯德基就是生产鸡翅 ...

  9. R语言学习笔记:choose、factorial、combn排列组合函数

    一.总结 组合数:choose(n,k) —— 从n个中选出k个 阶乘:factorial(k) —— k! 排列数:choose(n,k) * factorial(k) 幂:^ 余数:%% 整数商: ...

  10. Oracle学习笔记:实现select top N的方法

    由于Oracle不支持select top N语句,所以在Oracle中需要利用order by和rownum的组合来实现select top N的查询. rownum是记录表中数据编号的一个隐藏字段 ...