【Android】使用UncaughtExceptionHandler捕获全局异常

简介

当程序崩溃(Crash)的时候,默认是不对异常信息做处理的。如果想要把异常信息保存到本地文件中,或上传的服务器。那么就要借助UncaughtExceptionHandler这个类。

使用方法

一、实例化

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
public class CrashLogCatch {
public static final String THREAD_NAME_MAIN = "com.example.ABC"; //主线程名称
public static final String THREAD_NAME_REMOTE = "com.example.ABC:remote_service";

public static void initCrashLog(final Context context) {
final Thread.UncaughtExceptionHandler oriHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread thread, Throwable e) {
try {
StringBuilder buffer = new StringBuilder();
buffer.append(getCurProcessName(context) + "\n");
buffer.append("uncaught exception at ")
.append(new Date(System.currentTimeMillis()))
.append("\n");
buffer.append(ExceptionUtils.formatException(e));

String log = HttpLogController.getInstance().makeCrashLog(buffer.toString());
//发送崩溃日志
sendExceptionLog(log);
SdLog.dFileAlways("crash" + System.currentTimeMillis() + ".log", log);

if (Global.DEBUG) {
oriHandler.uncaughtException(thread, e); //debug模式,默认抛出异常
} else {
String threadName = thread.getName();

if (threadName.equals(THREAD_NAME_REMOTE)) {
android.os.Process.killProcess(android.os.Process.myPid()); //如果是service直接kill掉
} else if (threadName.equals(THREAD_NAME_MAIN)) {
oriHandler.uncaughtException(thread, e); //如果是主线程,抛出异常
}
}
} catch (Exception ex) {}
}
});
}

/**
* 获取当前进程名
*/
private static String getCurProcessName(Context context) {
try {
int pid = android.os.Process.myPid();
ActivityManager mActivityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager.getRunningAppProcesses()) {
if (appProcess.pid == pid){
return appProcess.processName;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}

/**
* 发送崩溃日志
*/
private static void sendExceptionLog(String log) {
try {
JSONObject jsonObject = new JSONObject(log);
Iterator keyIter = jsonObject.keys();
String key;
Object value;
HashMap<String, Object> valueMap = new HashMap<String, Object>();
while (keyIter.hasNext()) {
key = (String) keyIter.next();
value = jsonObject.get(key);
valueMap.put(key, value);
}
// 把异常信息发送到服务器
ComponentHolder.getLogController().sendLog(valueMap, LogType.EXCEPTION);
} catch (JSONException e) {
e.printStackTrace();
}
}
}

二、调用

1、对于整个Application

只要在指定的Application类的onCreate()回调中,把UncaughtExceptionHandler和Application的实例绑定在一起就可以了。关键代码如下:

1
2
3
4
5
6
7
8
public class MyApplication extends Application {

@Override
public void onCreate() {
CrashLogCatch.initCrashLog(this); //注意这里
super.onCreate();
}
}

这样,如果程序崩溃,错误日志就会被上传到服务器。

2、绑定Service 实例

1
2
3
4
5
6
7
8
public class MyService extends Service {

@Override
public void onCreate() {
Thread.currentThread().setName(CrashLogCatch.THREAD_NAME_REMOTE); //线程名称
CrashLogCatch.initCrashLog(this); //注意这里
}
}

3、绑定BroadcastReceiver实例

1
2
3
4
5
6
7
8
public class LaunchReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
Thread.currentThread().setName(CrashLogCatch.THREAD_NAME_REMOTE); //线程名称
CrashLogCatch.initCrashLog(context); //注意这里
}
}

参考资料

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2019 iTimeTraveler All Rights Reserved.

访客数 : | 访问量 :