一、全局捕获异常

为了解决这样的问题,我们需要能够及时的捕获异常,但要捕获的地方是在太多,因此,我们需要进行全局性的异常捕获,那么如何捕获全局异常呢?

答案是UncaughtExceptionHandler+Thread.setDefaultUncaughtExceptionHandler

1.UncaughtExceptionHandler是未捕获异常的处理接口,该类率先捕获异常

UncaughtExceptionHandler: 线程未捕获异常控制器是用来处理未捕获异常的。

如果程序出现了未捕获异常默认情况下则会出现强行关闭对话框

实现该接口并注册为程序中的默认未捕获异常处理

这样当未捕获异常发生时,就可以做些异常处理操作

例如:收集异常信息,发送错误报告 等。

二、代码实战

对于这个接口,我们需要进行实现

public class AppCrashHandler implements UncaughtExceptionHandler {

private Context mContext;

private Thread.UncaughtExceptionHandler mDefaultHandler;

/**防止多线程中的异常导致读写不同步问题的lock**/

private Lock lock = null;

/**本地保存文件日志**/

private final String CRASH_REPORTER_EXTENSION = ".crash";

/**日志tag**/

private final String STACK_TRACE = "logStackTrance";

/**保存文件名**/

private final String crash_pref_path ="app_crash_pref.xml";

private static final String OOM = "java.lang.OutOfMemoryError";

private static final String HPROF_FILE_PATH = Environment.getExternalStorageDirectory().getPath() + "/data_crash.hprof"

private AppCrashHandler()

{

lock = new ReentrantLock(true);

}

/**

* 获得单例对象

* @param context

* @return AppCrashHandler

*/

public static AppCrashHandler shareInstance(Context context){

AppCrashHandler crashhandler = AppCrashHandler.InstanceHolder.crashHandler;

crashhandler.initCrashHandler(context);

return crashhandler;

}

/**

* 使用初始化方法初始化,防止提前初始化或者重复初始化

* @param cxt

*/

private void initCrashHandler(Context cxt)

{

if(!hasInitilized()){

mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();

Thread.setDefaultUncaughtExceptionHandler(this);

mContext = cxt;

}

}

public interface InstanceHolder

{

public static AppCrashHandler crashHandler = new AppCrashHandler();

}

public static boolean isOOM(Throwable throwable){

Log.d(TAG, "getName:" + throwable.getClass().getName());

if(OOM.equals(throwable.getClass().getName())){

return true;

}else{

Throwable cause = throwable.getCause();

if(cause != null){

return isOOM(cause);

}

return false;

}

}

@Override

public void uncaughtException(Thread thread, Throwable ex) {

if(isOOM(throwable)){

try {

Debug.dumpHprofData(HPROF_FILE_PATH);

} catch (Exception e) {

Log.e(TAG, "couldn’t dump hprof", e);

}

}

if (!handleExceptionMessage(ex) && mDefaultHandler != null) {

// 如果用户没有处理则让系统默认的异常处理器来处理

mDefaultHandler.uncaughtException(thread, ex);

} else {

try {

Thread.sleep(3000);

} catch (InterruptedException e) {

Log.e(STACK_TRACE, "Error : ", e);

}

android.os.Process.killProcess(android.os.Process.myPid());

System.exit(10);

}

}

/**

* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. 开发者可以根据自己的情况来自定义异常处理逻辑

* @param ex

* @return true:如果处理了该异常信息;否则返回false

*/

private boolean handleExceptionMessage(Throwable ex)

{

if (ex == null)

{

return false;

}

// 使用Toast来显示异常信息

new Thread() {

@Override

public void run() {

// Toast 显示需要出现在一个线程的消息队列中

Looper.prepare();

Toast.makeText(mContext, "程序出错啦,即将退出", Toast.LENGTH_LONG).show();

Looper.loop();

}

}.start();

String fileName = mContext.getPackageName()+"-"+"appCrash-Exception"+ CRASH_REPORTER_EXTENSION;

String crashFileName = saveExceptionToFile(ex,fileName);

SharedPreferences.Editor editor = mContext.getSharedPreferences(crash_pref_path , Context.MODE_PRIVATE).edit();

editor.putString(STACK_TRACE, crashFileName);

editor.commit();

Log.d(STACK_TRACE, "errorLogPath="+crashFileName);

return true;

}

/**

* 是否已初始化

* @return

*/

public boolean hasInitilized()

{

return mContext!=null;

}

/**

* 保存错误信息到文件中

* @param ex

* @return

* @throws IOException

*/

private String saveExceptionToFile(Throwable ex,String fileName)

{

File saveFile = null;

PrintWriter printWriter = null;

try {

lock.tryLock();

if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))

{

File sdCardDir = Environment.getExternalStorageDirectory();//获取SDCard目录

saveFile = new File(sdCardDir, fileName);

}else{

saveFile =new File(mContext.getFilesDir(),fileName);

}

if(!saveFile.exists())

{

saveFile.createNewFile();

}

printWriter = new PrintWriter(saveFile);

String result = formatException(ex);

printWriter.write(result);

printWriter.flush();

Log.e("CrashException", result);

}catch(Exception e){

e.printStackTrace();

} finally{

if(printWriter!=null)

{

printWriter.close();

}

lock.unlock();

}

return saveFile!=null?saveFile.getAbsolutePath():null;

}

/**

* 格式化异常信息

* @param e

* @return

*/

@SuppressLint("SimpleDateFormat")

private  String  formatException(Throwable e)

{

StringBuilder sb = new StringBuilder();

StackTraceElement[] stackTrace = e.getStackTrace();

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

if (stackTrace!=null)

{

String  timeStramp =  sdf.format(new Date(System.currentTimeMillis()));

String format = String.format("DateTime:%s\nExceptionName:%s\n\n",timeStramp,e.getLocalizedMessage());

sb.append(format);

for (int i = 0; i

{

StackTraceElement traceElement = stackTrace[i];

String fileName = traceElement.getFileName();

int lineNumber = traceElement.getLineNumber();

String methodName = traceElement.getMethodName();

String className = traceElement.getClassName();

sb.append(String.format("%s\t%s[%d].%s \n",className,fileName,lineNumber,methodName));

}

sb.append(String.format("\n%s",e.getMessage()));

Writer stringWriter = new StringWriter();

PrintWriter pw = new PrintWriter(stringWriter);

e.printStackTrace(pw);

pw.flush();

pw.close();

sb.append("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");

sb.append(stringWriter.toString());

}

return sb.toString();

}

}

这里只保存了文件,一般来说,当app第二次启动时我们需要将该文件上传到网络,时间不是很充裕,这里上传暂时不贴代码了,时间充裕的话会及时补充,请保持关注吧

2.初始化,监听全局异常信息,这里需要继承Application,并替换系统默认的Application

public class BaseApplication extends Application

{

private  static BaseApplication instance = null;

private AppCrashHandler appCrashHandler = null;

@Override

public void onCreate() {

synchronized (this)

{

if(instance==null)

{

instance = this;

}

appCrashHandler =  AppCrashHandler.shareInstance(instance);

}

super.onCreate();

}

@Override

public void onConfigurationChanged(Configuration newConfig) {

super.onConfigurationChanged(newConfig);

}

}

修改清单文件

android:name="com.hali.luya.unitest.BaseApplication "

android:hardwareAccelerated="true"

android:icon="@drawable/app_logo"

android:logo="@drawable/app_logo"

android:label="@string/app_name"

android:configChanges="locale|keyboard|screenSize"

android:theme="@style/Theme.AppBaseTheme" >

三、腾讯Bugly

腾讯有一个bugly产品可以实现crash收集和处理,当然也可以同时使用UncaughtExceptionHandler,因为腾讯bugly虽然也实现了UncaughtExceptionHandler该回调,但腾讯bugly在捕获异常的同时也会调用你自己的UncaughtExceptionHandler。

目前腾讯的bugly不支持回调,但我申请到了腾讯的内测版支持回调。

public class BaseApplication extends Application

{

private  static Application instance = null;

private AppCrashHandler appCrashHandler = null;

private final String APP_CONTEXT_TAG = "appContext";

@Override

public void onCreate() {

synchronized (this)

{

if(instance==null)

{

instance = this;

}

appCrashHandler =  AppCrashHandler.shareInstance(instance);

UserStrategy strategy = new UserStrategy(instance); //App的策略Bean

strategy.setAppChannel(getPackageName());     //设置渠道

strategy.setAppVersion(getVersion());      //App的版本

strategy.setAppReportDelay(1000);  //设置SDK处理延时,毫秒

strategy.setDeviceID(GlobalUtil.getInstance().getDeviceID(instance));

strategy.setCrashHandleCallback(new AppCrashHandleCallback());

CrashReport.initCrashReport(instance, "900001335", true, strategy); //自定义策略生效,必须在初始化SDK前调用

CrashReport. setUserId("BBDTEK");

}

//shutDownLog();

super.onCreate();

}

@Override

public void onConfigurationChanged(Configuration newConfig) {

super.onConfigurationChanged(newConfig);

}

/**

* 获取版本号

* @return 当前应用的版本号

*/

public String getVersion() {

try {

PackageManager manager = this.getPackageManager();

PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);

String version = info.versionName;

return this.getString(R.string.app_version) + version;

} catch (Exception e) {

e.printStackTrace();

return this.getString(R.string.app_version);

}

}

private class AppCrashHandleCallback extends CrashHandleCallback //bugly回调

{

@Override

public synchronized Map onCrashHandleStart(int crashType, String errorType, String errorMessage, String errorStack)

{

String crashTypeName = null;

switch (crashType)

{

case CrashHandleCallback.CRASHTYPE_JAVA_CATCH:

crashTypeName = "JAVA_CATCH";

break;

case CrashHandleCallback.CRASHTYPE_JAVA_CRASH:

crashTypeName = "JAVA_CRASH";

break;

case CrashHandleCallback.CRASHTYPE_NATIVE:

crashTypeName = "JAVA_NATIVE";

break;

case CrashHandleCallback.CRASHTYPE_U3D:

crashTypeName = "JAVA_U3D";

break;

default:

{

crashTypeName = "unknown";

}

}

Log.e(APP_CONTEXT_TAG, "Crash Happen Type:" + crashType + " TypeName:" + crashTypeName);

Log.e(APP_CONTEXT_TAG, "errorType:" + errorType);

Log.e(APP_CONTEXT_TAG, "errorMessage:" + errorMessage);

Log.e(APP_CONTEXT_TAG, "errorStack:" + errorStack);

Map userDatas = super.onCrashHandleStart(crashType, errorType, errorMessage, errorStack);

if (userDatas == null)

{

userDatas = new HashMap();

}

userDatas.put("DEBUG", "TRUE");

return userDatas;

}

}

/**

* 关闭重要信息的日志

*/

private void shutDownLog()

{

LogUtils.allowE = false;

LogUtils.allowI = false;

LogUtils.allowV = false;

LogUtils.allowW = false;

LogUtils.allowWtf = false;

LogUtils.allowD = false;

}

}

try  doing it

android bug监控,Android UncaughtExceptionHandler 全局异常监控相关推荐

  1. Android UncaughtExceptionHandler 全局异常监控

    2019独角兽企业重金招聘Python工程师标准>>> 一.全局捕获异常 为了解决这样的问题,我们需要能够及时的捕获异常,但要捕获的地方是在太多,因此,我们需要进行全局性的异常捕获, ...

  2. Asp.net Core全局异常监控和记录日志

    前言 系统异常监控可以说是重中之重,系统不可能一直运行良好,开发和运维也不可能24小时盯着系统,系统抛异常后我们应当在第一时间收到异常信息.在Asp.net Core里我使用拦截器和中间件两种方式来监 ...

  3. 在Android中自定义捕获Application全局异常,可以替换掉系统的强制退出对话框(很有参考价值与实用价值)

    在Android中自定义捕获Application全局异常,可以替换掉系统的强制退出对话框(很有参考价值与实用价值) 参考文章: (1)在Android中自定义捕获Application全局异常,可以 ...

  4. 小程序异常监控及错误处理

    小程序异常监控收集 web端与小程序错误监控差异 在 Web 端监测的是页面完整的 url,而小程序端监测的是路由地址: 小程序页面属于app内部的页面,使用时已全部加载完毕,因此监控页面性能时不统计 ...

  5. 如何将数据指标异常监控和归因分析自动化

    目录 一.数据指标监控与归因目的 二.监控与归因框架 三.指标监控方法与实施 3.1 指标异常监控方法 3.2 梳理核心监控指标并进行异常监控 四.异常归因方法与实施 4.1 Adtributor根因 ...

  6. android捕获全局异常,并对异常做出处理

    2019独角兽企业重金招聘Python工程师标准>>> 在做项目时,经常会把错误利用异常抛出去,这样在开发时就可以通过手机抛的异常排查错误,很方便.但是当程序开发完毕,版本稳定,需要 ...

  7. Android开发之全局异常捕获

    Android开发之全局异常捕获 [转载请注明出处]本文出自付小华的博客 http://blog.csdn.net/klxh2009 今晨谷歌正式发布Android 8.0,新版本的Android O ...

  8. Windows平台监控Android App应用

    1.adb.exe 原理: adb 的运行原理是 PC 端的 adb server 与手机端的守护进程 adbd 建立连接,然后 PC 端的 adb client 通过 adb server 转发命令 ...

  9. Android全局异常捕捉器

    Android全局异常捕捉器主要是捕获应用在运行中无法预计的异常 1.首先要写一个MyCrashHandler实现UncaughtExceptionHandler package com.exampl ...

最新文章

  1. 八大主流Linux桌面环境特性汇总报告
  2. MySQL高级 - 复制 - 集群搭建
  3. java和Js中的类型转换_JavaScript 类型转换
  4. foreach循环符合就不往下走了_柴油发电机组冷却液循环故障解决方法
  5. win10下安装和卸载Ubuntu双系统
  6. 创建Session时会把含有Session ID 的Cookie对象加到响应对象上
  7. 「专题训练」k-Tree(CodeForces Round #247 Div.2 C)
  8. 聚类算法之DBSCAN
  9. 2011-7-3北京李庄儿童医院看病记
  10. mysql++简单应用_MySQL简单应用之视图(view)
  11. 淘淘商城第30讲——实现商品添加功能
  12. python程序画吉他和弦
  13. 【华为OD机试真题 python】特异性双端队列 | 最小调整顺序次数【2022 Q4 | 100分】
  14. 快消品行业存在痛点分析
  15. 让我们再聊聊浏览器资源加载优化
  16. 接收机的噪声来源与噪声分析
  17. OSPF高级特性 —— 管理距离(优先级)修改 + 外部路由的metric值的修改
  18. 【Unity开发小技巧】FMS有限状态机详解
  19. 数学基础 -- 基础定义(集合、实数集、映射、函数)
  20. 损失函数笔记(2)--对比损失

热门文章

  1. Apache#一文掌握Apache Web服务
  2. suggest的用法
  3. shell脚本语言(超全超详细)
  4. [PHP]CakePHP学习(一)
  5. C++ 右结合律与左结合律详解
  6. 如何查看浏览器网站的已保存的账户密码
  7. 原生js实现打开手机相册并上传文件到服务器
  8. SDcms后台拿webshell
  9. vue 路由里关于 TypeError: Converting circular structure to JSON 报错问题
  10. 云队友丨会谈加薪的人,一开口就赢了,让你薪资翻倍的3种方式,值得收藏!