工具-CrashHandler全局捕获异常

CrashHandler全局捕获异常

定义捕获异常的代码

CrashHandler.java

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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
import android.annotation.SuppressLint;
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.util.Log;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
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.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import rongshanghui.tastebychance.com.rongshanghui.MyApplication;


public class CrashHandler implements UncaughtExceptionHandler {
private static final String TAG = "ExceptionInfo";
@SuppressLint("SimpleDateFormat")
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HH_mm_ss");

private Context mContext;
private UncaughtExceptionHandler mDefaulHanler;

private static CrashHandler mInstance = new CrashHandler();

private Map<String, String> mLogInfo = new HashMap<String, String>();

public void init(Context context) {
mContext = context;
mDefaulHanler = Thread.getDefaultUncaughtExceptionHandler();
// 设置该CrashHandler为程序的默认处理器
Thread.setDefaultUncaughtExceptionHandler(this);
}

private CrashHandler() {

}

public static CrashHandler getInstance() {
return mInstance;
}

@Override
public void uncaughtException(Thread thread, Throwable ex) {
handleException(thread,ex);
}

public void handleException(Exception e){
Writer wr = new StringWriter();
PrintWriter err = new PrintWriter(wr);
e.printStackTrace(err);
Throwable cause = e.getCause();
while (cause != null){
cause.printStackTrace(err);
cause = cause.getCause();
}
err.close();
String result = wr.toString();
System.out.println("result ===================== " + result);
MyApplication.getAppContext().clearStatck();
}

public void handleException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaulHanler != null) {
// 如果自定义的没有处理则让系统默认的异常处理器来处理
mDefaulHanler.uncaughtException(thread, ex);
} else {
try {
// 如果处理了,让程序继续运行1秒再退出,保证文件保存并上传到服务器
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

MyApplication.getAppContext().onTerminate();
// 退出程序,注释下面的重启启动程序代码
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);

/*
* // 重新启动程序,注释上面的退出程序 Intent intent = new Intent();
* intent.setClass(mContext, MainActivity.class);
* intent.addFlag(Intent.FLAG_ACTIVITY_NEW_TASK);
* mContext.startActivity(intent);
* android.os.Process.killProcess(android.os.Process.myPid());
*/
}

public boolean handleException(Throwable paramThrowable) {
if (paramThrowable == null) {
return false;
}

new Thread(new Runnable() {

@Override
public void run() {
//Looper.prepare();
// Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出", 1000).show();
//Looper.loop();
}
}).start();

// 获取设备参数信息
getDeviceInfo(mContext);

if (MyApplication.IS_SAVE_ERRORLOG) {
// 保存日志文件
saveCrashLogToFile(paramThrowable);

}

return true;
}

/**
* 获取设备信息
*
* @param context
* @author ab
*/
private void getDeviceInfo(Context context) {
try {
PackageManager pm = context.getPackageManager();
PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
if (null != packageInfo) {
String versionName = packageInfo.versionName == null ? "null" : packageInfo.versionName;
String versionCode = packageInfo.versionCode + "";
String packageName = packageInfo.packageName;
mLogInfo.put("versionName", versionName);
mLogInfo.put("versionCode", versionCode);
mLogInfo.put("packageName", packageName);
}

} catch (NameNotFoundException e) {
e.printStackTrace();
}

// 反射机制
Field[] mFields = Build.class.getDeclaredFields();
// 迭代Build的字段key-value 此处的信息主要是为了在服务器端展示各种版本手机报错的原因
for (Field field : mFields) {
try {
field.setAccessible(true);
mLogInfo.put(field.getName(), field.get("").toString());
Log.d(TAG, field.getName() + ":" + field.get(""));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}

}

}

/**
* {将崩溃的Log保存到本地} TODO 可拓展,将Log上传至指定服务器路径
*
* @param paramThrowable
* @return
* @author ab
*/
private String saveCrashLogToFile(Throwable paramThrowable) {
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, String> entry : mLogInfo.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
sb.append(key + "=" + value + "\r\n");
}

Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
paramThrowable.printStackTrace(printWriter);
paramThrowable.printStackTrace();
Throwable throwable = paramThrowable.getCause();
// 迭代栈队列把所有的异常信息写入到writer中
while (throwable != null) {
throwable.printStackTrace(printWriter);
;
printWriter.append("\r\n");
throwable = throwable.getCause();
}
// 关闭流
printWriter.close();

String mResult = writer.toString();
sb.append(mResult);

// 保存文件,设置文件名
String mTime = sdf.format(new Date());
String mFileName = "SonChance_" + mTime + ".log";
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File mDirectory = new File(Environment.getExternalStorageDirectory() + File.separator + "ExceptionInfos");
Log.v(TAG, mDirectory.toString());
if (!mDirectory.exists()) {
mDirectory.mkdir();
}

try {
FileOutputStream fileOutputStream = new FileOutputStream(mDirectory + File.separator + mFileName);
fileOutputStream.write(sb.toString().getBytes());
fileOutputStream.close();

return mFileName;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

return null;
}

public void handlerError(String string){
// 保存文件,设置文件名
String mTime = sdf.format(new Date());
String mFileName = "SonChance_业务异常" + mTime + ".log";
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File mDirectory = new File(Environment.getExternalStorageDirectory() + File.separator + "ExceptionSonChance");
Log.v(TAG, mDirectory.toString());
if (!mDirectory.exists()) {
mDirectory.mkdir();
}

try {
FileOutputStream fileOutputStream = new FileOutputStream(mDirectory + File.separator + mFileName);
fileOutputStream.write(string.getBytes());

fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

异常代码的使用

MyApplication全局定义

1
2
3
4
<application
android:name=".MyApplication"
...>
</application>

调用:在MyApplication的onCreate()中添加

1
2
CrashHandler crashHandler = CrashHandler.getInstance();
crashHandler.init(this);

日志收集器