summerain0的个人博客

  • 首页
  • 意见反馈
  • 友情链接
  • 申请友联
每个Bug都有解决之法
在修了在修了_(:з」∠)_
  1. 首页
  2. Android
  3. 正文

自定义全局异常捕捉——保存至本地

2020年9月15日 288点热度 0人点赞 0条评论
浏览量: 192

开发安卓的小伙伴都遇到过APP突然崩溃,无响应的情况.如果发生在自己手中,那么还可以通过IDE查看错误日志,但是实际都是发生在用户手中,那么这个时候产生崩溃,无响应ANR异常就很麻烦.无从下手.因此,需要全局异常捕获.也就是对未知异常,程序员没有处理的异常进行处理,记录等便于分析查找原因.

MyUncaughtExceptionHandler.java
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
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
 
/**
* @ClassName MyUncaughtExceptionHandler
* @Description 全局捕捉异常
* @Author summerain0
* @Date 2020/9/11 15:31
*/
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    // 单例
    private static MyUncaughtExceptionHandler myUncaughtExceptionHandler;
    // 上下文
    private Context context;
    // 会输出到文件中
    private StringBuilder stringBuilder;
    // 系统异常处理器
    private Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler;
 
    public MyUncaughtExceptionHandler(Context context) {
        this.context = context;
    }
 
    // 获取单例
    public static synchronized MyUncaughtExceptionHandler getInstance(Context ctx) {
        if (myUncaughtExceptionHandler == null) {
            myUncaughtExceptionHandler = new MyUncaughtExceptionHandler(ctx);
        }
        return myUncaughtExceptionHandler;
    }
 
    // 初始化
    public void init() {
        defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }
 
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        if (throwable == null) {
            defaultUncaughtExceptionHandler.uncaughtException(thread, throwable);
        }
 
        // 创建集合对象
        stringBuilder = new StringBuilder();
 
        // 记录时间
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss.SSS", Locale.getDefault());
        String date = simpleDateFormat.format(new Date());
        addMessage("崩溃时间", date);
 
        // 记录应用版本信息
        try {
            PackageManager pm = context.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
            addMessage("版本名", pi.versionName);
            addMessage("版本号", pi.versionCode);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            addMessage("error", "记录版本信息失败!" + e.getMessage());
        }
 
        // 记录设备信息
        Field[] fields = Build.class.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                Object obj = field.get(null);
                if (obj != null) {
                    addMessage(field.getName(), obj);
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                addMessage("error", "记录设备信息失败!" + e.getMessage());
            }
        }
 
        // 添加分隔符
        addMessage(null, "==============================================================");
        addMessage(null, "========================   崩溃日志   =========================");
        addMessage(null, "==============================================================");
 
        // 记录崩溃信息
        Writer writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        throwable.printStackTrace(printWriter);
        Throwable cause = throwable.getCause();
        while (cause != null) {
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }
        printWriter.close();
        addMessage(null, writer.toString());
 
        // 生成路径,保存至/Android/data/包名,无需读写权限
        try {
            File root = context.getExternalFilesDir("log");
            String filename = date + ".log";
            File file = new File(root, filename);
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(stringBuilder.toString().getBytes());
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
            defaultUncaughtExceptionHandler.uncaughtException(thread, throwable);
        }
    }
 
    // 添加数据
    private void addMessage(String key, Object obj) {
        // 对数组做一下处理
        if (obj instanceof String[]) {
            String[] list = (String[]) obj;
            ArrayList<String> array = new ArrayList<>(Arrays.asList(list));
            stringBuilder.append(key).append("=").append(array.toString()).append("\n");
        }
        // 其他的都直接添加
        if (key == null) {
            stringBuilder.append(obj)
                    .append("\n");
        } else {
            stringBuilder.append(key)
                    .append("=")
                    .append(obj)
                    .append("\n");
        }
    }
 
}
 
MyApplication.java
MyApplication.java
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import android.app.Application;
 
/**
* @ClassName MyApplication
* @Description TODO
* @Author summerain0
* @Date 2020/9/11 14:00
*/
public class MyApplication extends Application {
    public static final String TAG = "MyApplication";
 
    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化异常处理器
        MyUncaughtExceptionHandler.getInstance(MyApplication.this).init();
    }
}
 
AndroidManifest.xml
XHTML
1
2
3
4
<application
        android:name=".MyApplication"
        ....>
</application>
 
标签: Android 教程
最后更新:2020年10月17日

summerain0

保持饥渴的专注,追求最佳的品质

打赏 点赞
< 上一篇
下一篇 >

文章评论

取消回复

summerain0

保持饥渴的专注,追求最佳的品质

最新 热点 随机
最新 热点 随机
什么?你是学生?还不快来白嫖JetBrains全家桶? Android Studio的图标库出现Nothing to show问题 GitHub在线下载加速网址集合 Android Material Design全面解析(一)- MaterialButton篇 Android自定义全局异常捕获——Activity形式 自定义全局异常捕捉——保存至本地
自定义全局异常捕捉——保存至本地 Android自定义全局异常捕获——Activity形式 Android Studio的图标库出现Nothing to show问题 什么?你是学生?还不快来白嫖JetBrains全家桶? Android Material Design全面解析(一)- MaterialButton篇 GitHub在线下载加速网址集合
标签聚合
Material Design 工具 教程 Android
实用工具
  • 免费API工具
友情链接
  • AIDE教程网
  • 极坛
  • Ptcraft
  • 沐川的博客

COPYRIGHT © 2020 summerain0的个人博客. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

闽ICP备19012197号