Android - CrashHandler 全局异常捕获器

官网介绍如下:Thread.UncaughtExceptionHandler (Java Platform SE 8 )

用于线程因未捕获异常而突然终止时调用的处理程序接口。当线程由于未捕获异常而即将终止时,Java虚拟机将使用thread . getuncaughtexceptionhandler()查询该线程的UncaughtExceptionHandler,并调用该处理程序的uncaughtException方法,将线程和异常作为参数传递。

如果一个线程没有显式设置它的UncaughtExceptionHandler,那么它的ThreadGroup对象充当它的UncaughtExceptionHandler。如果ThreadGroup对象对处理异常没有特殊要求,它可以将调用转发给默认的未捕获异常处理程序。

 基于此点,我们可以将其应用为整个app出现异常后,没有在此处添加异常处理的时候,捕获异常并进行通用处理。

1、首先实现 Thread.UncaughtExceptionHandler 接口并创建一个单例
class CrashHandler : Thread.UncaughtExceptionHandler {companion object {private const val TAG = "CrashHandler"//外部存储目录private val INNER_PATH = Environment.getExternalStorageDirectory().path//自定义文件夹private const val SELF_FILE = "/lichang/"//文件名称private const val CRASH_FILE = "crash_error.log"@SuppressLint("SimpleDateFormat")private val formatter: DateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")val sInstance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {CrashHandler()}}
...
2、添加初始化方法
    private var infos = mutableMapOf<String, String>()private var mContext: Context? = nullprivate var mDefaultHandler: Thread.UncaughtExceptionHandler? = null//初始化fun init(context: Context) {this.mContext = contextthis.mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler()Thread.setDefaultUncaughtExceptionHandler(this)}
3、重写 uncaughtException() 方法
    override fun uncaughtException(thread: Thread, throwable: Throwable) {if ((!handleException(throwable)) && (this.mDefaultHandler != null)) {//如果代码中没有处理交给系统处理this.mDefaultHandler!!.uncaughtException(thread, throwable);return;}//延时3秒杀死进程Log.e(TAG, "Process will be killed in 2 seconds!");try {Thread.sleep(2000)} catch (e: InterruptedException) {Log.e(TAG, "error : ", e)}android.os.Process.killProcess(android.os.Process.myPid())exitProcess(1)}/*** 处理异常信息* @param throwable* @return*/private fun handleException(throwable: Throwable?): Boolean {if (throwable == null) {return false}object : Thread() {override fun run() {Looper.prepare()//在此处处理出现异常的情况throwable.printStackTrace()Log.e(TAG, "出现了未捕获异常!!!")Looper.loop()}}.start()this.mContext?.let { collectDeviceInfo(it) }saveCrashInfo2File(throwable)return true}/*** 收集设备信息* @param context*/private fun collectDeviceInfo(context: Context) {val packageInfo: PackageInfo?try {packageInfo = context.packageManager.getPackageInfo(context.packageName,PackageManager.GET_ACTIVITIES)if (packageInfo != null) {val versionName =if (packageInfo.versionName == null) "null" else packageInfo.versionNameval versionCode = packageInfo.versionCode.toString() + ""this.infos["versionName"] = versionNamethis.infos["versionCode"] = versionCode}} catch (e: PackageManager.NameNotFoundException) {Log.e(TAG, "an error occured when collect package info", e)}//获取Build信息val declaredFields: Array<Field> = Build::class.java.declaredFieldsval length = declaredFields.sizevar i = 0while (i < length) {val declaredField: Field = declaredFields[i]try {declaredField.setAccessible(true)this.infos[declaredField.getName()] = declaredField.get(null).toString()} catch (e: Exception) {Log.e(TAG, "an error occured when collect crash info", e)}i += 1}}/*** 保存crash信息到文件* @param throwable* @return*/private fun saveCrashInfo2File(throwable: Throwable): String? {var throwable: Throwable? = throwableval crashInfos = StringBuffer()//添加分隔行crashInfos.append("\r\n")//添加crash时间crashInfos.append("Crash Time")crashInfos.append("=")crashInfos.append(formatter.format(Date(System.currentTimeMillis())))crashInfos.append("\r\n")val iterator: Iterator<Map.Entry<String, String>> = infos.entries.iterator()var next: Map.Entry<String, String>? = nullwhile (iterator.hasNext()) {next = iterator.next()crashInfos.append(next.key)crashInfos.append("=")crashInfos.append(next.value)crashInfos.append("\r\n")}val exceptionInfo = StringWriter()val printWriter = PrintWriter(exceptionInfo)throwable!!.printStackTrace(printWriter)//循环获取throwable的栈信息throwable = throwable.causewhile (throwable != null) {throwable.printStackTrace(printWriter)throwable = throwable.cause}printWriter.close()crashInfos.append(exceptionInfo.toString())try {System.currentTimeMillis()if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {val file = File("$INNER_PATH$SELF_FILE")if (!file.exists()) {file.mkdirs()}val fos = FileOutputStream("$INNER_PATH$SELF_FILE$CRASH_FILE", true)fos.write(crashInfos.toString().toByteArray())fos.close()}return CRASH_FILE} catch (e: Exception) {Log.e(TAG, "an error occured while writing file...", e)}return null}
4、在 BaseApplication 里实现,activity 里也行,但毕竟 application 生命周期更长,可以更好的捕获异常位置。
CrashHandler.sInstance.init(this)
5、验证手动抛出一个error,“ throw Exception("error")”

logcat 输出内容如下:

10:48:38.287 AndroidRuntime            D  Shutting down VM
10:48:38.293 AndroidRuntime            E  FATAL EXCEPTION: mainProcess: com.lichang.source, PID: 29787java.lang.RuntimeException: java.lang.reflect.InvocationTargetExceptionat com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:563)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)Caused by: java.lang.reflect.InvocationTargetExceptionat java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:553)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003) Caused by: java.lang.Exception: errorat com.lichang.source.MainActivity.onCreate$lambda$0(MainActivity.kt:23)at com.lichang.source.MainActivity.$r8$lambda$1d06GL5SsQcwKha8s7cR5MexWzU(Unknown Source:0)at com.lichang.source.MainActivity$$ExternalSyntheticLambda0.onClick(Unknown Source:0)at android.view.View.performClick(View.java:7448)at android.view.View.performClickInternal(View.java:7421)at android.view.View.access$3700(View.java:838)at android.view.View$PerformClick.run(View.java:28870)at android.os.Handler.handleCallback(Handler.java:938)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loopOnce(Looper.java:201)at android.os.Looper.loop(Looper.java:288)at android.app.ActivityThread.main(ActivityThread.java:7941)at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:553) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003) 
10:48:38.299 System.err                W  java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
10:48:38.299 System.err                W  	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:563)
10:48:38.299 System.err                W  	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
10:48:38.300 System.err                W  Caused by: java.lang.reflect.InvocationTargetException
10:48:38.300 System.err                W  	at java.lang.reflect.Method.invoke(Native Method)
10:48:38.300 System.err                W  	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:553)
10:48:38.300 System.err                W  	... 1 more
10:48:38.300 System.err                W  Caused by: java.lang.Exception: error
10:48:38.301 System.err                W  	at com.lichang.source.MainActivity.onCreate$lambda$0(MainActivity.kt:23)
10:48:38.301 System.err                W  	at com.lichang.source.MainActivity.$r8$lambda$1d06GL5SsQcwKha8s7cR5MexWzU(Unknown Source:0)
10:48:38.301 System.err                W  	at com.lichang.source.MainActivity$$ExternalSyntheticLambda0.onClick(Unknown Source:0)
10:48:38.301 System.err                W  	at android.view.View.performClick(View.java:7448)
10:48:38.302 System.err                W  	at android.view.View.performClickInternal(View.java:7421)
10:48:38.302 System.err                W  	at android.view.View.access$3700(View.java:838)
10:48:38.302 System.err                W  	at android.view.View$PerformClick.run(View.java:28870)
10:48:38.302 System.err                W  	at android.os.Handler.handleCallback(Handler.java:938)
10:48:38.302 System.err                W  	at android.os.Handler.dispatchMessage(Handler.java:99)
10:48:38.303 System.err                W  	at android.os.Looper.loopOnce(Looper.java:201)
10:48:38.303 System.err                W  	at android.os.Looper.loop(Looper.java:288)
10:48:38.303 System.err                W  	at android.app.ActivityThread.main(ActivityThread.java:7941)
10:48:38.303 System.err                W  	... 3 more
10:48:38.303 CrashHandler              E  出现了未捕获异常!!!
10:48:38.472 CrashHandler              E  Process will be killed in 2 seconds!
---------------------------- PROCESS ENDED (29787) for package com.lichang.source ----------------------------
10:48:40.473 Process                   I  Sending signal. PID: 29787 SIG: 9

记录如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/337111.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

路由黑洞和黑洞路由的区别

路由黑洞&#xff1a; 路由黑洞是一种现象&#xff0c;一般是在网络边界做汇总回程路由的时候产生的一种不太愿意出现的现象&#xff0c;就是汇总的时候有时会有一些不在内网中存在的网段&#xff0c;但是又包含在汇总后的网段中&#xff0c;如果在这个汇总的边界设备上同时还配…

Java面试之并发篇(一)

1、前言 本篇主要总结JAVA面试中关于并发相关的高频面试题。本篇的面试题基于网络整理&#xff0c;和自己编辑。在不断的完善补充哦。 2、简述程序、进程、线程、的基本概念&#xff1f; 2.1、程序 程序&#xff0c;是含有指令和数据的文件&#xff0c;被存储在磁盘或其他的…

变压器

一、变压器的作用 电压变换&#xff1a;变压器可以改变交流电压的大小&#xff0c;从而满足不同设备的需要。通过变压器的降压和升压功能&#xff0c;可以将电压升高或降低到合适的范围&#xff0c;实现远距离输电、电能分配和设备安全运行的目的。 电流变换&#xff1a;变压器…

解决 rasa 中 slot 不能为中文的问题

解决 rasa 中 slot 不能为中文的问题 定位问题解决办法 定位问题 slots:姓名:type: textmappings:- type: custom如上的 slot 配置&#xff0c;在 rasa train 时会报以下错误&#xff1a; YamlValidationException: Failed to validate D:\project\python\rasa_test\y\domain…

Python爬取哈尔滨旅游爆火视频数据并进行可视化分析

前言 哈尔滨作为中国北方的重要城市&#xff0c;独特的冰雪风情和丰富的文化底蕴而受到游客的青睐。随着抖音等短视频平台的兴起&#xff0c;越来越多关于哈尔滨旅游的视频在网络上出现文章旨在利用Python编程语言&#xff0c;从音视频网站上抓取哈尔滨旅游抖音相关视频数据&a…

java基础之异常练习题

异常 1.Java 中所有的错误/异常都继承自 Throwable类&#xff1b;在该类的子类中&#xff0c; Error 类表示严重的底层错误&#xff0c; 对于这类错误一般处理的方式是 直接报告并终止程序 &#xff1b; Exception 类表示异常。 2.查阅API&#xff0c;完成以下填空&#xff1a;…

RK3568驱动指南|第十篇 热插拔-第112章 热插拔简介

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

window mysql5.7 搭建主从同步环境

window 搭建mysql5.7数据库 主从同步 主节点 配置文件my3308.cnf [mysql] # 设置mysql客户端默认字符集 default-character-setutf8mb4[mysqld] server-id8 #server-uuidbc701be9-ac71-11ee-9e35-b06ebf511956 log-binD:\mysql_5.7.19\mysql-5.7.19-winx64\mysql-bin binlog-…

22nxxz

难度简单,适合练手! 期末考试前最后一篇博客,还是很感谢范老师,范老师帮我突破了后台的思路mua! 一、请检查窝点中的手机检材,回答以下问题 直接分析不行,sd卡需要解压缩 该OPPO手机的IMEI是:860370043989014,860370049389006860370049389014,8603700493890068603700…

安卓 APK 如何查看公钥与签名 MD5 值、JadxGUI 工具的使用。

下载地址 https://gitcode.com/skylot/jadx/overview?utm_sourcecsdn_github_accelerator&isLogin1 也可以在这里下载 https://download.csdn.net/download/u010843503/88725345

Web缓存代理

目录 前瞻 web缓存代理的工作机制 web缓存代理的作用 常见的Web缓存代理应用 squid、Varinsh和Nginx有什么区别&#xff0c;工作中你怎么选择&#xff1f; 数据库缓存代理应用 Nginx 缓存代理 CDN缓存代理 简介 原理 CDN对网络的优化作用主要体现在如下几个方面 CDN…

phpstorm配置ftp

1 选择设置ftp 2设置自动上传