崩溃日志显示Toast并输出至SD Card - 适配Android10

1、工具类

异常捕获Handler

public class CrashHandler implements Thread.UncaughtExceptionHandler {private Context mContext;// 用来存储应用信息和设备信息private Map<String, String> mInfo = new LinkedHashMap<>();// 默认的未捕获异常处理器private Thread.UncaughtExceptionHandler mDefaultHandler;/*** instance       实例* INSTANCE_LOCK  互斥锁*/private static CrashHandler instance = null;private static final Object INSTANCE_LOCK = new Object();/*** 获取实例** @return*/public static CrashHandler getInstance() {if (instance == null) {synchronized (INSTANCE_LOCK) {if (instance == null) {instance = new CrashHandler();}}}return instance;}/*** 初始化** @param context*/public void init(Context context) {mContext = context.getApplicationContext();// 获取默认的未捕获异常处理器mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 设置CrashHandler为默认的未捕获异常处理器Thread.setDefaultUncaughtExceptionHandler(this);}/*** 捕获异常** @param t* @param ex*/@Overridepublic void uncaughtException(@NonNull Thread t, @NonNull Throwable ex) {// 处理异常handleException(ex);try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}// 结束应用if (mDefaultHandler != null) {mDefaultHandler.uncaughtException(t, ex);} else {System.exit(1);}}/*** 处理异常 - 输出 Toast 及 输出到 sd card** @param ex*/private void handleException(Throwable ex) {final Throwable e = ex;// Toast提示出现异常new Thread() {@Overridepublic void run() {Looper.prepare();Toast.makeText(mContext, e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();Looper.loop();}}.start();// 收集应用信息和设备信息collectInfo();// 保存崩溃信息到SD卡AndroidUtils.saveErrInfoToGalleryByScopedStorage(mContext, outputErrorLogInfo(ex));}/*** 错误日志** @param ex* @return*/private String outputErrorLogInfo(Throwable ex) {String deviceInfo = "";for (String key : mInfo.keySet()) {deviceInfo += key + "  : " + mInfo.get(key) + "\n";}return "Error Info : \n" + ex.getLocalizedMessage() + "\n\n" + "Device Info : \n" + deviceInfo;}/*** 收集信息*/private void collectInfo() {// 收集BuildConfig类信息
//        collectClassInfo(BuildConfig.class);// 收集Build.VERSION类信息collectClassInfo(Build.VERSION.class);// 收集Build类信息collectClassInfo(Build.class);}/*** 收集信息** @param cls*/private void collectClassInfo(Class cls) {Field[] fields = cls.getDeclaredFields();for (Field field : fields) {try {field.setAccessible(true);mInfo.put(field.getName(), field.get(null).toString());} catch (IllegalAccessException e) {e.printStackTrace();}}}
}

崩溃日志输出至sd card

public class AndroidUtils {public static final String TAG = "AndroidUtils";/*** ERROR_LOG_FILE_PATH_1 --- Android 10 及以上错误日志存储路径* ERROR_LOG_FILE_PATH_2 --- Android 10 以下错误日志存储路径* ERROR_LOG_FILE_NAME   --- 错误日志文件名*/public static final String ERROR_LOG_FILE_PATH_1 = "Download/UAT Error Logs";public static final String ERROR_LOG_FILE_PATH_2 = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "UAT Error Logs";public static final String ERROR_LOG_FILE_NAME = "errLog";/*** 错误日志输出到 sdk card* <p>* Android 10 及以上日志路径 --- /storage/sdcard/Download/UAT Error Logs* Android 10 以下日志路径   --- /storage/emulated/0/UAT Error Logs** @param context* @param logContent* @return*/public static boolean saveErrInfoToGalleryByScopedStorage(Context context, String logContent) {long timestamp = System.currentTimeMillis();String time = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date(timestamp));String fileName = ERROR_LOG_FILE_NAME + "_" + time + ".txt";FileOutputStream fos = null;OutputStream os = null;try {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {//Android 10 及以上ContentValues values = new ContentValues();values.put(MediaStore.Downloads.DISPLAY_NAME, fileName);//设置文件类型values.put(MediaStore.Downloads.MIME_TYPE, "text/plain");//这个方法只可在Android10的手机上执行,设置路径values.put(MediaStore.Downloads.RELATIVE_PATH, ERROR_LOG_FILE_PATH_1);Uri external = MediaStore.Downloads.EXTERNAL_CONTENT_URI;// 写入文件Uri uri = context.getContentResolver().insert(external, values);if (uri != null) {os = context.getContentResolver().openOutputStream(uri);os.write(logContent.getBytes());os.flush();return true;}} else {//Android 10 以下File dir = new File(ERROR_LOG_FILE_PATH_2);if (!dir.exists()) {dir.mkdir();}File file = new File(dir, fileName);if (!file.exists()) {file.createNewFile();}fos = new FileOutputStream(file);fos.write(logContent.getBytes());fos.flush();return true;}} catch (Exception e) {e.printStackTrace();Log.e(TAG, Log.getStackTraceString(e));} finally {closeIO(fos);closeIO(os);}return false;}/*** 关闭流,普通不严重的可采用此函数关闭*/public static void closeIO(Closeable... closeables) {if (null == closeables || closeables.length <= 0) {return;}for (Closeable cb : closeables) {try {if (null == cb) {continue;}cb.close();} catch (Exception e) {Log.e(TAG, Log.getStackTraceString(e));}}}
}

2、使用

public class MyApplication extends Application {@Overridepublic void onCreate() {super.onCreate();//崩溃日志CrashHandler.getInstance().init(this);}
}

程序崩溃闪退之后,在文件管理器中搜索UAT Error Logs文件夹

CrashHandler相关推荐

  1. 使用CrashHandler来获取应用的crash信息

    源码地址https://github.com/king1039/android-art-res/tree/master/Chapter_13/CrashTest/src/com/ryg/crashte ...

  2. android随机崩溃莫名其妙,Android CrashHandler编写自己的异常捕获的方法

    平时写代码,我们可能会抛出各种异常,这些异常有些是我们测试过程中发现进行解决的,但是也有一些异常是我们未知的,不论是代码的逻辑问题还是Android本身底层的一些bug,我们都需要及时了解并进行解决. ...

  3. setTextColor的几种方式 CrashHandler使用demo:

    目录 setTextColor的几种方式 CrashHandler使用demo: setTextColor的几种方式 方式一:<.......android:color="#FFFFF ...

  4. 自定义CrashHandler轻轻松松让你查看程序崩溃

    今天测试遇到崩溃,而我又没办法查看,于是老司机教了我一招. 下面是CrashHandler类: package com.bbk.bfcupload.bfcuploadtestdemo.util;imp ...

  5. 全局手动捕获崩溃异常错误CrashHandler【工具类直接可用】

    废话不多哔哔,直接上工具类 /*** 全局捕获异常* 当程序发生Uncaught异常的时候,有该类来接管程序,并记录错误日志*/ public class CrashHandler_Ma {publi ...

  6. 学习和使用程序捕捉异常 CrashHandler以及ACRA

    今天,我来回顾一下如何友好的处理程序异常. 目前,我学习两种方法去实现友好界面处理异常 方法一:CrashHandler(老的使用办法) 方法二:ACRA(Google推荐) 1.CrashHandl ...

  7. 自定义CrashHandler 处理Uncaught异常

    人都是自己先开始放弃自己 的 坐了一晚上火车,担心了一晚上,生怕对面的大爷打呼噜把他自己吵醒了,,, 题归正传,今天写一遍关于APP crash后重写crash类抓取日志及 平滑退出的东东. 首先介绍 ...

  8. Android 保存崩溃日志到本地目录下

    代码如下可以直接复制过去,别人的代码修改了下 package com.hly.rtxt; import android.annotation.SuppressLint; import android. ...

  9. Android 常见工具类封装

    1,MD5工具类: public class MD5Util {public final static String MD5(String s) {char hexDigits[] = { '0', ...

最新文章

  1. 哈希表处理冲突的方法
  2. tensorflow2.0降级及如何从别的版本升到2.0
  3. JPG图片EXIF信息提取工具exif
  4. 积木赛尔号机器人_赛尔号11年,圣灵谱尼从章鱼变花臂少年,最终成为了老父亲...
  5. 现存问题以及解决方案:在ASP.NET AJAX中从客户端向服务器端传送DataTable
  6. 一起来学Spring Cloud | 第五章:熔断器 ( Hystrix)
  7. 不得了了!Python 又爆出重大 Bug!
  8. redis特点单进程单线程高性能服务器,Redis为什么是单线程?Redis又为什么这么快!...
  9. spark2.0.1安装部署及使用jdbc连接基于hive的sparksql
  10. effective C++ 条款 3:尽可能使用const
  11. yum安转软件包提示nokey错误时的处理办法。
  12. 云计算机房防雷规范,弱电机房设计内容规范大全
  13. 光纤猫可做无线打印服务器吗,光猫自带的天线,这些天线都有什么用呢?是无线功能吗?...
  14. 美版iphone更新系统无服务器,iPhone 升级系统提示无法检查更新如何解决?
  15. 微信小程序选择图片更换背景
  16. 概要设计说明书的书写
  17. Android设置TabLayout及下划线宽度
  18. 学会了C语言究竟能干什么呢?
  19. 永磁同步直流无刷电机空间矢量SPWM,SVPWM
  20. c语言less函数,less用法总结

热门文章

  1. 饥饿的小易(枚举+广度优先遍历(BFS))
  2. 梵想 S690MQ 4TB固态尝鲜,我的磁盘空间又充裕了
  3. 04 无穷大量与无穷小量
  4. 如何画出一张合格的技术架构图? 1
  5. 我和我的输入提示----XHTree.h
  6. Qt编写物联网管理平台9-数据查询
  7. Python 代码编程问题总结
  8. JAVAWEB天气预报 中国气象网API(WebServices)
  9. 梁宁产品思维学习-2机会判断(1点线面体的战略选择)
  10. 新手必备!免费原画素材网站!