Android 全局异常捕获之CrashHandler

一个App上线或者投入到生产环境的时候崩溃了,还不知道是什么原因,这肯定是开发者的痛…所以肯定要加入全局异常捕获,如果项目较大的话,可以考虑加入第三方诸如友盟的崩溃统计插件,以达到异常捕获的效果!

Crash,可以理解为崩溃、垮台,通常来讲就是App运行期间发生了不可预料的错误,虽然在经历发布之前,测试人员进行了大量的测试,但是并不能保证App的正常运行,总会或多或少有一些BUG的。

Java的Thread中有一个UncaughtExceptionHandler接口,该接口的作用主要是为了当Thread 因未捕获的异常而突然终止时,调用处理程序。我们可以通过setDefaultUncaughtExceptionHandler方法,来改变异常默认处理程序。

实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package  com.yuyh.utils;
 
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  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.HashMap;
import  java.util.Map;
 
/**
* UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告.
*
* Created by yuyuhang on 15/12/7.
*/
public  class  CrashHandler  implements  UncaughtExceptionHandler {
 
      //系统默认的UncaughtException处理类
      private  Thread.UncaughtExceptionHandler mDefaultHandler;
      //CrashHandler实例
      private  static  CrashHandler INSTANCE;
      //程序的Context对象
      private  Context mContext;
      //用来存储设备信息和异常信息
      private  Map<String, String> infos =  new  HashMap<String, String>();
 
      private  CrashHandler() {
      }
 
      /**
        * 获取CrashHandler实例 ,单例模式
        */
      public  static  CrashHandler getInstance() {
           if  (INSTANCE ==  null )
                 INSTANCE =  new  CrashHandler();
                 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) {
                            LogUtils.e(e.toString());
                      }
                      //退出程序
                      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 ;
                }
                //收集设备参数信息
                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 ) {
                            String versionName = pi.versionName ==  null  "null"  : pi.versionName;
                            String versionCode = pi.versionCode +  "" ;
                            infos.put( "versionName" , versionName);
                            infos.put( "versionCode" , versionCode);
                      }
                 catch  (NameNotFoundException e) {
                      LogUtils.e( "CrashHandleran.NameNotFoundException---> 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());
                      catch  (Exception e) {
                            LogUtils.e( "CrashHandler.NameNotFoundException---> an error occured when collect crash info" , e);
                      }
                 }
           }
 
           /**
             * 保存错误信息到文件中
             *
             * @param ex
             * @return 返回文件名称, 便于将文件传送到服务器
             */
            private  String saveCrashInfo2File(Throwable ex) {
 
                  StringBuffer sb =  new  StringBuffer();
                  sb.append( "---------------------sta--------------------------" );
                  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);
                  sb.append( "--------------------end---------------------------" );
                  LogUtils.e(sb.toString());
                  return  null ;
          }
}

然后我们在Application中,对CrashHandler进行初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import  android.app.Application;
import  android.content.Context;
 
import  com.yuyh.utils.CrashHandler;
 
/**
* Created by yuyuhang on 15/12/7.
*/
public  class  App  extends  Application {
 
      public  static  Context mContext;
 
      @Override
      public  void  onCreate() {
           super .onCreate();
           CrashHandler crashHandler = CrashHandler.getInstance();
           crashHandler.init(getApplicationContext());
           mContext =  this ;
      }
}

这样的话,当程序代码中并未捕获异常,但发生了异常的时候,就会交由CrashHandler进行处理,异常信息可以保存到日志文件中。日志文件记录请参考:Android 日志打印工具类 可显示打印所在的方法和行号

这样子,就能把异常信息及其异常发生所在的位置,保存在日志文件中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值