欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 全局异常捕获实例详解

程序员文章站 2023-12-03 12:29:58
android 全局异常捕获 今天就来说说作为程序猿的我们每天都会遇到的东西bug,出bug不可怕可怕的是没有出bug时的堆栈信息,那么对于bug的信息收集就显得尤为重要...

android 全局异常捕获

今天就来说说作为程序猿的我们每天都会遇到的东西bug,出bug不可怕可怕的是没有出bug时的堆栈信息,那么对于bug的信息收集就显得尤为重要了,一般用第三方bugly或者友盟等等都能轻易收集,但是由于公司不让使用第三方,而安卓正好有原生的异常收集类uncaughtexceptionhandler,那么今天博客就从这个类开始.

uncaughtexceptionhandler见名知意,即他是处理我们未捕获的异常,具体使用分两步

1.实现我们自己的异常处理类

public class crashhandler implements thread.uncaughtexceptionhandler {
  @override
  public void uncaughtexception(thread thread, throwable ex) {

  }
}

需要我们实现thread.uncaughtexceptionhandler接口当有未捕获的异常的时候会回调uncaughtexception(thread thread, throwable ex)方法

2.设置该crashhandler为系统默认的

thread.setdefaultuncaughtexceptionhandler(crashhandler);

以上只是使用步骤的介绍,具体项目中的使用我直接贴代码

在application中初始化

package com.zly.www.basedemo.base;

import android.app.application;
import android.content.context;
import com.zly.www.basedemo.exception.crashhandler;

/**
 * created by zly on 2016/6/11.
 */
public class appapplication extends application {


  private static context mcontext;

  @override
  public void oncreate() {
    super.oncreate();
    this.mcontext = this;
    crashhandler.getinstance().init(this);//初始化全局异常管理
  }

  public static context getcontext(){
    return mcontext;
  }
}

crashhandler 实现类如下

package com.zly.www.basedemo.exception;

import android.content.context;
import android.content.pm.packageinfo;
import android.content.pm.packagemanager;
import android.os.build;
import android.os.environment;
import android.os.looper;
import android.util.log;
import android.widget.toast;

import com.zly.www.basedemo.utils.appmanager;

import java.io.file;
import java.io.fileoutputstream;
import java.io.printwriter;
import java.io.stringwriter;
import java.io.writer;
import java.lang.reflect.field;
import java.text.simpledateformat;
import java.util.date;
import java.util.hashmap;
import java.util.map;

/**
 * 全局异常捕获
 * created by zly on 2016/7/3.
 */
public class crashhandler implements thread.uncaughtexceptionhandler {

  /**
   * 系统默认uncaughtexceptionhandler
   */
  private thread.uncaughtexceptionhandler mdefaulthandler;

  /**
   * context
   */
  private context mcontext;

  /**
   * 存储异常和参数信息
   */
  private map<string,string> paramsmap = new hashmap<>();

  /**
   * 格式化时间
   */
  private simpledateformat format = new simpledateformat("yyyy-mm-dd-hh-mm-ss");

  private string tag = this.getclass().getsimplename();

  private static crashhandler minstance;

  private crashhandler() {

  }

  /**
   * 获取crashhandler实例
   */
  public static synchronized crashhandler getinstance(){
    if(null == minstance){
      minstance = new crashhandler();
    }
    return minstance;
  }

  public void init(context context){
    mcontext = context;
    mdefaulthandler = thread.getdefaultuncaughtexceptionhandler();
    //设置该crashhandler为系统默认的
    thread.setdefaultuncaughtexceptionhandler(this);
  }

  /**
   * uncaughtexception 回调函数
   */
  @override
  public void uncaughtexception(thread thread, throwable ex) {
    if(!handleexception(ex) && mdefaulthandler != null){//如果自己没处理交给系统处理
      mdefaulthandler.uncaughtexception(thread,ex);
    }else{//自己处理
      try {//延迟3秒杀进程
        thread.sleep(3000);
      } catch (interruptedexception e) {
        log.e(tag, "error : ", e);
      }
      //退出程序
      appmanager.getappmanager().appexit(mcontext);
    }

  }

  /**
   * 收集错误信息.发送到服务器
   * @return 处理了该异常返回true,否则false
   */
  private boolean handleexception(throwable ex) {
    if (ex == null) {
      return false;
    }
    //收集设备参数信息
    collectdeviceinfo(mcontext);
    //添加自定义信息
    addcustominfo();
    //使用toast来显示异常信息
    new thread() {
      @override
      public void run() {
        looper.prepare();
        toast.maketext(mcontext, "程序开小差了呢..", toast.length_short).show();
        looper.loop();
      }
    }.start();
    //保存日志文件
    savecrashinfo2file(ex);
    return true;
  }


  /**
   * 收集设备参数信息
   * @param ctx
   */
  public void collectdeviceinfo(context ctx) {
    //获取versionname,versioncode
    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 + "";
        paramsmap.put("versionname", versionname);
        paramsmap.put("versioncode", versioncode);
      }
    } catch (packagemanager.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);
        paramsmap.put(field.getname(), field.get(null).tostring());
      } catch (exception e) {
        log.e(tag, "an error occured when collect crash info", e);
      }
    }
  }

  /**
   * 添加自定义参数
   */
  private void addcustominfo() {

  }

  /**
   * 保存错误信息到文件中
   *
   * @param ex
   * @return 返回文件名称,便于将文件传送到服务器
   */
  private string savecrashinfo2file(throwable ex) {

    stringbuffer sb = new stringbuffer();
    for (map.entry<string, string> entry : paramsmap.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 = format.format(new date());
      string filename = "crash-" + time + "-" + timestamp + ".log";
      if (environment.getexternalstoragestate().equals(environment.media_mounted)) {
        string path = environment.getexternalstoragedirectory().getabsolutepath() + "/crash/";
        file dir = new file(path);
        if (!dir.exists()) {
          dir.mkdirs();
        }
        fileoutputstream fos = new fileoutputstream(path + filename);
        fos.write(sb.tostring().getbytes());
        fos.close();
      }
      return filename;
    } catch (exception e) {
      log.e(tag, "an error occured while writing file...", e);
    }
    return null;
  }
}

activity管理类

package com.zly.www.basedemo.utils;

import java.util.stack;

import android.app.activity; 
import android.app.activitymanager; 
import android.content.context;

/**
 * activity管理类:用于管理activity和退出程序
 * created by zly on 2016/6/11.
 */
public class appmanager { 

  // activity栈 
  private static stack<activity> activitystack; 
  // 单例模式 
  private static appmanager instance; 

  private appmanager() { 
  } 

  /** 
   * 单一实例 
   */ 
  public static appmanager getappmanager() { 
    if (instance == null) { 
      instance = new appmanager(); 
    } 
    return instance; 
  } 

  /** 
   * 添加activity到堆栈 
   */ 
  public void addactivity(activity activity) { 
    if (activitystack == null) { 
      activitystack = new stack<activity>(); 
    } 
    activitystack.add(activity); 
  } 

  /** 
   * 获取当前activity(堆栈中最后一个压入的) 
   */ 
  public activity currentactivity() { 
    activity activity = activitystack.lastelement(); 
    return activity; 
  } 

  /** 
   * 结束当前activity(堆栈中最后一个压入的) 
   */ 
  public void finishactivity() { 
    activity activity = activitystack.lastelement(); 
    finishactivity(activity); 
  } 

  /** 
   * 结束指定的activity 
   */ 
  public void finishactivity(activity activity) { 
    if (activity != null) { 
      activitystack.remove(activity); 
      activity.finish(); 
      activity = null; 
    } 
  } 

  /** 
   * 结束指定类名的activity 
   */ 
  public void finishactivity(class<?> cls) { 
    for (activity activity : activitystack) { 
      if (activity.getclass().equals(cls)) { 
        finishactivity(activity);
        break;
      } 
    } 
  } 

  /** 
   * 结束所有activity 
   */ 
  public void finishallactivity() { 
    for (int i = 0; i < activitystack.size(); i++) { 
      if (null != activitystack.get(i)) { 
        activitystack.get(i).finish(); 
      } 
    } 
    activitystack.clear(); 
  } 

  /** 
   * 退出应用程序 
   */ 
  public void appexit(context context) { 
    try { 
      finishallactivity(); 
      //退出程序
      android.os.process.killprocess(android.os.process.mypid());
      system.exit(1); 
    } catch (exception e) { 
    } 
  } 
} 

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!