• android全局捕获异常错误


    1. 使用自定义application,在oncreate生命周期里面代理全局异常捕获程序
    2. 自定义Thread.UncaughtExceptionHandler类,在uncaughtException方法里面对异常进行捕获和处理

    自定义application

    新建自定义application类

    1. public class myApp extends Application {
    2.     @Override
    3.     public void onCreate() {
    4.         super.onCreate();
    5.    //初始化异常捕获自定义类
    6.        ExceptionCrashHandler ex= ExceptionCrashHandler.getInstance();
    7.        ex.init(getApplicationContext());
    8.     }
    9. }

    在AndroidMianifest.xml里面修改application表情的name为自定义application的类名字

    1. <application
    2.     android:name=".myApp"
    3.    省略其他代码—>

    自定义线程异常捕获类

    捕获到异常后常见的处理方式

    • 携带异常信息,跳转到新的acitivity(并在新的activity里面发起ajax收集错误信息,并引导用户回到首页),停止当前activity
    • 发起ajax请求,后闪退
    1. /**
    2. * 单例的设计模式的异常捕捉
    3. */
    4. public class ExceptionCrashHandler implements Thread.UncaughtExceptionHandler{
    5.     private  Thread.UncaughtExceptionHandler mDefaultException;
    6.     ProgressDialog dialog;
    7.     public  static  ExceptionCrashHandler getInstance(){
    8.         if(mInstance==null){
    9.             //用来解决多线程并发问题
    10.             synchronized (ExceptionCrashHandler.class){
    11.                 mInstance=new ExceptionCrashHandler();
    12.             }
    13.         }
    14.         return mInstance;
    15.     }
    16.     private  Context mContext;
    17.     public  void  init(Context context){
    18.         this.mContext=context;
    19.         //把全局的异常捕获设置为当前类
    20.         Thread.currentThread().setUncaughtExceptionHandler(this);
    21. //当前线程的异常捕获函数
    22.         mDefaultException=Thread.getDefaultUncaughtExceptionHandler();
    23.     }
    24.     @Override
    25.     public void uncaughtException(@NonNull Thread thread, @NonNull Throwable ex) {
    26.     //全局异常捕获
    27.         Log.d(TAG, "全局异常捕获:"+  ex.toString());
    28.     }
    29. }

    调用默认未捕获异常的处理方式

    调用默认未捕获异常的处理方式,也就是闪退,如果没有调用UI视图会处于卡顿的情况,

    可以在调用它之前发起ajax,ajax响应后,再调用它

    mDefaultException.uncaughtException(thread,ex);

    新线程

    因为当前主线程卡住了,所以最好是开一个新的线程来处理ajax,如下

    1. /**
    2.      * 自定义错误处理,收集错误信息 将异常信息保存 发送错误报告等操作均在此完成.
    3.      * 但是无法再访问activity
    4.      * @param ex
    5.      * @return true:如果处理了该异常信息;否则返回false.
    6.      */
    7.     private boolean handleExample(Throwable ex) {
    8.         // 如果已经处理过这个Exception,则让系统处理器进行后续关闭处理
    9.         if (ex == null){
    10.             return false;
    11.         }
    12.         new Thread(() -> {
    13.             // Toast 显示需要出现在一个线程的消息队列中
    14.             Looper.prepare();
    15.             Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出", Toast.LENGTH_SHORT).show();
    16.             Looper.loop();
    17.         }).start();
    18.         return true;
    19.     }

    为什么这里用  Toast.makeText而不是ProgressDialog

    因为ui线程卡住了,无法进行任何的ui操作,而 Toast.makeText是不依赖ui的,ProgressDialog需要activity

    如果是跳转新页面的方案,在跳转activivity后关闭崩溃的进程即可

    1. private  void  jump(String txt){
    2.     // 跳转到崩溃提示Activity
    3.     Intent intent = new Intent(mContext, MainActivity2.class);
    4.     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    5.     String chancel=getChannelInfo();
    6.     Bundle bundle = new Bundle();
    7.     //渠道信息
    8.     bundle.putString("chancel", chancel);
    9.     //错误信息
    10.     bundle.putString("err", txt);
    11.     intent.putExtras(bundle);
    12.   //  Log.d(TAG, "jump: "+txt);
    13.     mContext.startActivity(intent);
    14.     // 关闭已奔溃的app进程
    15.     System.exit(0);
    16. }

    其他的辅助方法

    获取AndroidMainifest.xml自定义属性

    1. private  String getChannelInfo(){
    2.     ApplicationInfo info;
    3.     String chancelInfo="";
    4.     try{
    5.         PackageManager pm = mContext.getPackageManager();
    6.         info = pm.getApplicationInfo( mContext.getPackageName(), PackageManager.GET_META_DATA);
    7.         chancelInfo=(String) info.metaData.get("appChannel");
    8.         Log.d(TAG, "getChannelInfo: "+chancelInfo);
    9.     }
    10.     catch (Exception e){
    11.         Log.d(TAG, "getChannelInfo: ");
    12.         e.printStackTrace();
    13.     }
    14.     return chancelInfo;
    15. }

    xml: