Android开发如何使用UncaughtExceptionHandler捕获程序崩溃错误信息?

本文主要是介绍Android开发如何使用UncaughtExceptionHandler捕获程序崩溃错误信息?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

关于UncaughtExceptionHandler这个异常接口的作用,我想对于大多数的APP来说一般都是为了给用户更好的体验,在我们程序崩溃时不让其直接报一个错误信息界面然后退出我们的应用程序,而是让我们的应用程序在崩溃时直接跳回到我们的应用程序首页

下面是博主在工作中的使用,主要是在我们应用程序崩溃退出时进行一个错误log分析,将错误信息保存到我们机器SD卡上,然后进行错误分析。代码如下:

package com.asir.mediaplayer;import java.io.BufferedReader; 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
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.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;import android.content.Context;
import android.content.pm.ApplicationInfo;
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.os.Looper;
import android.util.Log;
import android.widget.Toast;public class CrashHandler implements UncaughtExceptionHandler {public static final String TAG = "CrashHandler";public static final String PATH_SD = "/mnt/sdcard/log/";// 系统默认的UncaughtException处理类private Thread.UncaughtExceptionHandler mDefaultHandler;// CrashHandler实例private static CrashHandler instance;// 程序的Context对象private Context mContext;// 用来存储设备信息和异常信息private Map<String, String> infos = new HashMap<String, String>();// 用于格式化日期,作为日志文件名的一部分private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");/** 保证只有一个CrashHandler实例 */private CrashHandler() {}/** 获取CrashHandler实例 ,单例模式 */public static CrashHandler getInstance() {if (instance == null)instance = new CrashHandler();return instance;}/*** 初始化*/public void init(Context context) {mContext = context;// 获取系统默认的UncaughtException处理器mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 设置该CrashHandler为程序的默认处理器Thread.setDefaultUncaughtExceptionHandler(this);}/*** 当UncaughtException发生时会转入该函数来处理*/@Overridepublic void uncaughtException(Thread thread, Throwable ex) {Log.e(TAG, "___________ erre start");if (!handleException(ex) && mDefaultHandler != null) {// 如果用户没有处理则让系统默认的异常处理器来处理mDefaultHandler.uncaughtException(thread, ex);} else {try {Thread.sleep(5000);} catch (InterruptedException e) {Log.e(TAG, "error : ", e);}// 退出程序android.os.Process.killProcess(android.os.Process.myPid());System.exit(1);}}public String getApplicationName() {PackageManager packageManager = null;ApplicationInfo applicationInfo = null;try {packageManager = mContext.getApplicationContext().getPackageManager();applicationInfo = packageManager.getApplicationInfo(mContext.getPackageName(), 0);} catch (PackageManager.NameNotFoundException e) {applicationInfo = null;}String applicationName = (String) packageManager.getApplicationLabel(applicationInfo);return applicationName;}/*** 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.* * @param ex* @return true:如果处理了该异常信息;否则返回false.*/private boolean handleException(Throwable ex) {if (ex == null) {return false;}// 收集设备参数信息collectDeviceInfo(mContext);// 使用Toast来显示异常信息new Thread() {@Overridepublic void run() {Looper.prepare();String applicationName = getApplicationName();applicationName += "程序出现异常,即将退出";Toast.makeText(mContext, applicationName, Toast.LENGTH_LONG).show();Looper.loop();}}.start();// 保存日志文件saveCatchInfo2File(ex, PATH_SD);return true;}
/*** 收集设备参数信息* * @param ctx*/public void collectDeviceInfo(Context ctx) {try {PackageManager pm = ctx.getPackageManager();PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);if (pi != null) {String versionName = pi.versionName == null ? "null" : pi.versionName;String versionCode = pi.versionCode + "";infos.put("versionName", versionName);infos.put("versionCode", versionCode);}} catch (NameNotFoundException e) {Log.e(TAG, "an error occured when collect package info", e);}Field[] fields = Build.class.getDeclaredFields();for (Field field : fields) {try {field.setAccessible(true);infos.put(field.getName(), field.get(null).toString());Log.d(TAG, field.getName() + " : " + field.get(null));} catch (Exception e) {Log.e(TAG, "an error occured when collect crash info", e);}}}/*** 保存错误信息到文件中* * @param ex* @return 返回文件名称,便于将文件传送到服务器*/private String saveCatchInfo2File(Throwable ex, String path) {StringBuffer sb = new StringBuffer();for (Map.Entry<String, String> entry : infos.entrySet()) {String key = entry.getKey();String value = entry.getValue();sb.append(key + "=" + value + "\n");}Writer writer = new StringWriter();PrintWriter printWriter = new PrintWriter(writer);ex.printStackTrace(printWriter);Throwable cause = ex.getCause();while (cause != null) {cause.printStackTrace(printWriter);cause = cause.getCause();}printWriter.close();String result = writer.toString();sb.append(result);try {long timestamp = System.currentTimeMillis();String time = formatter.format(new Date());String fileName = "crash-" + time + "-" + timestamp + ".log";if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {File dir = new File(path);if (!dir.exists()) {dir.mkdirs();}FileOutputStream fos = new FileOutputStream(path + fileName);fos.write(sb.toString().getBytes());Log.e(TAG, "___________wirt erre info");// 发送给开发人员// sendCrashLog2PM(path+fileName);fos.close();}return fileName;} catch (Exception e) {Log.e(TAG, "an error occured while writing file...", e);}return null;}
/*** 将捕获的导致崩溃的错误信息发送给开发人员* * 目前只将log日志保存在sdcard 和输出到LogCat中,并未发送给后台。*/private void sendCrashLog2PM(String fileName) {if (!new File(fileName).exists()) {Toast.makeText(mContext, "日志文件不存在!", Toast.LENGTH_SHORT).show();return;}FileInputStream fis = null;BufferedReader reader = null;String s = null;try {fis = new FileInputStream(fileName);reader = new BufferedReader(new InputStreamReader(fis, "GBK"));while (true) {s = reader.readLine();if (s == null)break;// 由于目前尚未确定以何种方式发送,所以先打出log日志。Log.i("info", s.toString());}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally { // 关闭流try {reader.close();fis.close();} catch (IOException e) {e.printStackTrace();}}}}

这个类相当的简单,没什么好解释的了! 那么用法如下,在我们的工程目录自己创建的Application的oncreate方法中执行下面的代码即可:

CrashHandler catchHandler = CrashHandler.getInstance();catchHandler.init(this);

这篇关于Android开发如何使用UncaughtExceptionHandler捕获程序崩溃错误信息?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1122344

相关文章

Java程序进程起来了但是不打印日志的原因分析

《Java程序进程起来了但是不打印日志的原因分析》:本文主要介绍Java程序进程起来了但是不打印日志的原因分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java程序进程起来了但是不打印日志的原因1、日志配置问题2、日志文件权限问题3、日志文件路径问题4、程序

Spring Boot 集成 Quartz并使用Cron 表达式实现定时任务

《SpringBoot集成Quartz并使用Cron表达式实现定时任务》本篇文章介绍了如何在SpringBoot中集成Quartz进行定时任务调度,并通过Cron表达式控制任务... 目录前言1. 添加 Quartz 依赖2. 创建 Quartz 任务3. 配置 Quartz 任务调度4. 启动 Sprin

Android实现悬浮按钮功能

《Android实现悬浮按钮功能》在很多场景中,我们希望在应用或系统任意界面上都能看到一个小的“悬浮按钮”(FloatingButton),用来快速启动工具、展示未读信息或快捷操作,所以本文给大家介绍... 目录一、项目概述二、相关技术知识三、实现思路四、整合代码4.1 Java 代码(MainActivi

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

Java使用SLF4J记录不同级别日志的示例详解

《Java使用SLF4J记录不同级别日志的示例详解》SLF4J是一个简单的日志门面,它允许在运行时选择不同的日志实现,这篇文章主要为大家详细介绍了如何使用SLF4J记录不同级别日志,感兴趣的可以了解下... 目录一、SLF4J简介二、添加依赖三、配置Logback四、记录不同级别的日志五、总结一、SLF4J

使用Python实现一个优雅的异步定时器

《使用Python实现一个优雅的异步定时器》在Python中实现定时器功能是一个常见需求,尤其是在需要周期性执行任务的场景下,本文给大家介绍了基于asyncio和threading模块,可扩展的异步定... 目录需求背景代码1. 单例事件循环的实现2. 事件循环的运行与关闭3. 定时器核心逻辑4. 启动与停

如何使用Nginx配置将80端口重定向到443端口

《如何使用Nginx配置将80端口重定向到443端口》这篇文章主要为大家详细介绍了如何将Nginx配置为将HTTP(80端口)请求重定向到HTTPS(443端口),文中的示例代码讲解详细,有需要的小伙... 目录1. 创建或编辑Nginx配置文件2. 配置HTTP重定向到HTTPS3. 配置HTTPS服务器

Java使用ANTLR4对Lua脚本语法校验详解

《Java使用ANTLR4对Lua脚本语法校验详解》ANTLR是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件,下面就跟随小编一起看看Java如何使用ANTLR4对Lua脚本... 目录什么是ANTLR?第一个例子ANTLR4 的工作流程Lua脚本语法校验准备一个Lua Gramm

Java Optional的使用技巧与最佳实践

《JavaOptional的使用技巧与最佳实践》在Java中,Optional是用于优雅处理null的容器类,其核心目标是显式提醒开发者处理空值场景,避免NullPointerExce... 目录一、Optional 的核心用途二、使用技巧与最佳实践三、常见误区与反模式四、替代方案与扩展五、总结在 Java

Android Mainline基础简介

《AndroidMainline基础简介》AndroidMainline是通过模块化更新Android核心组件的框架,可能提高安全性,本文给大家介绍AndroidMainline基础简介,感兴趣的朋... 目录关键要点什么是 android Mainline?Android Mainline 的工作原理关键