zoukankan      html  css  js  c++  java
  • 保存全局Crash报告

    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 +  " " );
            }
            
            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




  • 相关阅读:
    Ubuntu系统Anaconda安装Pytorch,教你如何优雅的安装环境(1-5)
    优雅的装系统------安装MacOS 10.13.5系统教程
    关闭Ubuntu系统更新方法
    毫秒钟搞定anaconda环境使用清华镜像安装OpenCV,教你如何优雅的安装环境(1-4)
    Ubuntu16.04安装Anaconda3并配置国内镜像,教你优雅的安装环境(1-3)
    Anaconda常用命令
    Ubuntu16.04安装CUDA10.2+cuDNN7.6.5(福利区),教你如何优雅的安装环境(1-2)
    Ubuntu16.04安装NVIDIA驱动,教你如何优雅的安装环境(1-1)
    简述 QPS、TPS、并发用户数、吞吐量关系
    Springboot验证注解@vaild的使用
  • 原文地址:https://www.cnblogs.com/Amandaliu/p/3196435.html
Copyright © 2011-2022 走看看