1
+ package com .jingewenku .abrahamcaijin .commonutil ;
2
+
3
+ import android .content .Context ;
4
+ import android .content .pm .PackageInfo ;
5
+ import android .content .pm .PackageManager ;
6
+ import android .os .Build ;
7
+ import android .os .Environment ;
8
+ import android .os .Looper ;
9
+ import android .util .Log ;
10
+ import android .widget .Toast ;
11
+
12
+ import java .io .*;
13
+ import java .lang .reflect .Field ;
14
+ import java .text .DateFormat ;
15
+ import java .text .SimpleDateFormat ;
16
+ import java .util .Date ;
17
+ import java .util .HashMap ;
18
+ import java .util .Locale ;
19
+ import java .util .Map ;
20
+
21
+
22
+ /**
23
+ * @Description:主要功能:UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告.
24
+ * @Prject: CommonUtilLibrary
25
+ * @Package: com.jingewenku.abrahamcaijin.commonutil
26
+ * @author: AbrahamCaiJin
27
+ * @date: 2017年06月01日 10:49
28
+ * @Copyright: 个人版权所有
29
+ * @Company:
30
+ * @version: 1.0.0
31
+ */
32
+
33
+ /*
34
+ * public class AndroidUtilsApplication extends Application {
35
+ * public void onCreate() {
36
+ * super.onCreate();
37
+ * //崩溃处理
38
+ * CrashHandlerUtil crashHandlerUtil = CrashHandlerUtil.getInstance();
39
+ * crashHandlerUtil.init(this);
40
+ * crashHandlerUtil.setCrashTip("很抱歉,程序出现异常,即将退出!");
41
+ * }
42
+ * }
43
+ */
44
+
45
+ public class CrashHandlerUtil implements Thread .UncaughtExceptionHandler {
46
+
47
+ public static final String TAG = "CrashHandlerUtil" ;
48
+
49
+ //系统默认的UncaughtException处理类
50
+ private Thread .UncaughtExceptionHandler mDefaultHandler ;
51
+ //CrashHandler实例
52
+ private static CrashHandlerUtil INSTANCE = new CrashHandlerUtil ();
53
+ //程序的Context对象
54
+ private Context mContext ;
55
+ //用来存储设备信息和异常信息
56
+ private Map <String , String > infos = new HashMap <>();
57
+
58
+ //用于格式化日期,作为日志文件名的一部分
59
+ private DateFormat formatter = new SimpleDateFormat ("yyyy-MM-dd-HH-mm-ss" , Locale .CHINA );
60
+ private String crashTip = "很抱歉,程序出现异常,即将退出!" ;
61
+
62
+ public String getCrashTip () {
63
+ return crashTip ;
64
+ }
65
+
66
+ public void setCrashTip (String crashTip ) {
67
+ this .crashTip = crashTip ;
68
+ }
69
+
70
+ /**
71
+ * 保证只有一个CrashHandler实例
72
+ */
73
+ private CrashHandlerUtil () {
74
+ }
75
+
76
+ /**
77
+ * 获取CrashHandler实例 ,单例模式
78
+ *
79
+ * @return 单例
80
+ */
81
+ public static CrashHandlerUtil getInstance () {
82
+ return INSTANCE ;
83
+ }
84
+
85
+ /**
86
+ * 初始化
87
+ *
88
+ * @param context 上下文
89
+ */
90
+ public void init (Context context ) {
91
+ mContext = context ;
92
+ //获取系统默认的UncaughtException处理器
93
+ mDefaultHandler = Thread .getDefaultUncaughtExceptionHandler ();
94
+ //设置该CrashHandler为程序的默认处理器
95
+ Thread .setDefaultUncaughtExceptionHandler (this );
96
+ }
97
+
98
+ /**
99
+ * 当UncaughtException发生时会转入该函数来处理
100
+ *
101
+ * @param thread 线程
102
+ * @param ex 异常
103
+ */
104
+ @ Override
105
+ public void uncaughtException (Thread thread , Throwable ex ) {
106
+ if (!handleException (ex ) && mDefaultHandler != null ) {
107
+ //如果用户没有处理则让系统默认的异常处理器来处理
108
+ mDefaultHandler .uncaughtException (thread , ex );
109
+ } else {
110
+ try {
111
+ Thread .sleep (3000 );
112
+ } catch (InterruptedException e ) {
113
+ Log .e (TAG , "error : " , e );
114
+ e .printStackTrace ();
115
+ }
116
+ //退出程序
117
+ AppManager .getAppManager ().exitApp ();
118
+ }
119
+ }
120
+
121
+ /**
122
+ * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
123
+ *
124
+ * @param throwable 异常
125
+ * @return true:如果处理了该异常信息;否则返回false.
126
+ */
127
+ private boolean handleException (final Throwable throwable ) {
128
+ if (throwable == null ) {
129
+ return false ;
130
+ }
131
+ //使用Toast来显示异常信息
132
+ new Thread () {
133
+ @ Override
134
+ public void run () {
135
+ Looper .prepare ();
136
+ throwable .printStackTrace ();
137
+ Toast .makeText (mContext , getCrashTip (), Toast .LENGTH_LONG ).show ();
138
+ Looper .loop ();
139
+ }
140
+ }.start ();
141
+ //收集设备参数信息
142
+ collectDeviceInfo (mContext );
143
+ //保存日志文件
144
+ saveCrashInfo2File (throwable );
145
+ return true ;
146
+ }
147
+
148
+ /**
149
+ * 收集设备参数信息
150
+ *
151
+ * @param ctx 上下文
152
+ */
153
+ public void collectDeviceInfo (Context ctx ) {
154
+ try {
155
+ PackageManager pm = ctx .getPackageManager ();
156
+ PackageInfo pi = pm .getPackageInfo (ctx .getPackageName (), PackageManager .GET_ACTIVITIES );
157
+ if (pi != null ) {
158
+ String versionName = pi .versionName == null ? "null" : pi .versionName ;
159
+ String versionCode = pi .versionCode + "" ;
160
+ infos .put ("versionName" , versionName );
161
+ infos .put ("versionCode" , versionCode );
162
+ }
163
+ } catch (PackageManager .NameNotFoundException e ) {
164
+ Log .e (TAG , "an error occured when collect package info" , e );
165
+ }
166
+ Field [] fields = Build .class .getDeclaredFields ();
167
+ for (Field field : fields ) {
168
+ try {
169
+ field .setAccessible (true );
170
+ infos .put (field .getName (), field .get (null ).toString ());
171
+ Log .d (TAG , field .getName () + " : " + field .get (null ));
172
+ } catch (Exception e ) {
173
+ Log .e (TAG , "an error occured when collect crash info" , e );
174
+ }
175
+ }
176
+ }
177
+
178
+ /**
179
+ * 保存错误信息到文件中
180
+ *
181
+ * @param ex 异常
182
+ * @return 返回文件名称, 便于将文件传送到服务器
183
+ */
184
+ private String saveCrashInfo2File (Throwable ex ) {
185
+
186
+ StringBuffer sb = new StringBuffer ();
187
+ for (Map .Entry <String , String > entry : infos .entrySet ()) {
188
+ String key = entry .getKey ();
189
+ String value = entry .getValue ();
190
+ sb .append (key + "=" + value + "\n " );
191
+ }
192
+
193
+ Writer writer = new StringWriter ();
194
+ PrintWriter printWriter = new PrintWriter (writer );
195
+ ex .printStackTrace (printWriter );
196
+ Throwable cause = ex .getCause ();
197
+ while (cause != null ) {
198
+ cause .printStackTrace (printWriter );
199
+ cause = cause .getCause ();
200
+ }
201
+ printWriter .close ();
202
+ String result = writer .toString ();
203
+ sb .append (result );
204
+ try {
205
+ long timestamp = System .currentTimeMillis ();
206
+ String time = formatter .format (new Date ());
207
+ String fileName = "crash-" + time + "-" + timestamp + ".log" ;
208
+ if (Environment .getExternalStorageState ().equals (Environment .MEDIA_MOUNTED )) {
209
+ String path = Environment .getExternalStorageDirectory ().getPath () + "/crash/" ;
210
+ AppLogMessageMgr .d ("path=" + path );
211
+ File dir = new File (path );
212
+ if (!dir .exists ()) {
213
+ dir .mkdirs ();
214
+ }
215
+ FileOutputStream fos = new FileOutputStream (path + fileName );
216
+ fos .write (sb .toString ().getBytes ());
217
+ fos .close ();
218
+ }
219
+ return fileName ;
220
+ } catch (Exception e ) {
221
+ Log .e (TAG , "an error occured while writing file..." , e );
222
+ }
223
+ return null ;
224
+ }
225
+
226
+ }
0 commit comments