zoukankan      html  css  js  c++  java
  • 自己定义Application的未捕获异常处理

        近期由于工作原因。进行Android应用开发时发现应用在出现类似空指针等异常时,抛出未被捕获的异常。Android系统有默认的未捕获异常处理器,默认行为是结束对应的线程,但并不会直接退出程序,并且在应用还有后台Service时。服务还一直在执行,假设service在请求网络时还会抛出一些异常信息,并且在未全然退出的应用中再次使用还会进一步导致异常,这样对于用户体验来说实在不好。

        因此,须要在应用无论什么情况下出现异常后应该直接退出应用,然后重新启动应用。网上搜了非常多资料。非常多都不能非常好解决问题,由于Android可能会启动非常多Activity,而在结束应用进程之前应该finish全部Task中的Activity,否则会出现一些不想要的结果,当然还要结束后台的Service。

        Android中有一个Thread.UncaughtExceptionHandler接口,须要实现该接口。并实现当中的uncaughtException函数。以下直接贴上相关代码:

    public class MyCrashHandler implements Thread.UncaughtExceptionHandler {
    private static final String TAG = "MyCaughtException";
    // 应用
    private MyApplication mApplication;
    // 系统默认的未捕捉异常处理器
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    // 自己定义的未捕捉异常处理器
    private static MyCrashHandler gCaughtException;

    /**
    * 单例模式的保障
    */
    private CEPM360CrashHandler() { 

    }

    /**
    * 单例模式
    * @param application
    * @return
    */
        public static synchronized MyCrashHandler getInstance(Application application) {
            if (gCaughtException == null) {
            gCaughtException = new MyCrashHandler(application);
            }
            return gCaughtException;
        }

        /**
         * 构造函数
         * @param application
         */
    private MyCrashHandler(Application application) {
    mApplication = (MyApplication) application;
    // 获取系统默认的UncaughtExceptionHandler
    mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
    // 设置异常处理器
    Thread.setDefaultUncaughtExceptionHandler(this);
    }


    /**
    * 未捕获异常处理函数
    */
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
    Log.e(TAG, "Ocurrs uncaughtException!");
    // 打印堆栈
                   ex.printStackTrace();

    Intent intent = new Intent(mApplication, MyService.class);
    if (!handleException(ex) && mDefaultHandler != null) {
    mDefaultHandler.uncaughtException(thread, ex);
    } else {
    try {
    mApplication.stopService(intent);
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }

            // 退出程序后,启动应用第一个LoginActivity
            intent = new Intent(mApplication, MainActivity.class);
            PendingIntent restartIntent = 
            PendingIntent.getActivity(mApplication,
            0, 
            intent, 
            Intent.FLAG_ACTIVITY_NEW_TASK);
            AlarmManager alarmManager = (AlarmManager) 
            mApplication.getSystemService(Context.ALARM_SERVICE);
            alarmManager.set( AlarmManager.RTC, 
            System.currentTimeMillis() + 1000, 
            restartIntent);
            
            mApplication.exit();
    }

    /**
    * 异常处理函数
    * @param ex
    * @return
    */
    private boolean handleException(Throwable ex) {
    if (ex == null) {
    return false;
    }

    // 重新启动一个线程显示异常信息
    new Thread() {
    @Override
    public void run() {
    Looper.prepare();
    showExceptionToast();
    Looper.loop();
    }
    }.start();
    return true;
    }

    /**
    * 显示发生异常Toast,确认后重新启动应用
    */
    private void showExceptionToast() {
    Toast toast = Toast.makeText(mApplication, 
    "非常抱歉,“CEPM360”已停止执行,即将重新启动", Toast.LENGTH_SHORT);
    // 设置居中显示
    toast.setGravity(Gravity.CENTER, 0, 0);

    LinearLayout toastLayout = (LinearLayout) toast.getView();
    toastLayout.setLayoutDirection(LinearLayout.HORIZONTAL);

    ImageView image = new ImageView(mApplication);
    image.setImageResource(R.drawable.exception_picture);
    toastLayout.addView(image, 0);

    toast.setView(toastLayout);
    toast.show();
    }
    }

        上面是自己定义的未捕获异常处理器。要想让其发挥作用,须要配合Application,默认情况下Android不须要你手动实现或实例化一个APPlication对象。但自己定义未捕获异常处理中要finish全部的activity。但在application中没有对应的Task相关API,就没有办法拿到当前应用在Task中的全部Activity,因此须要我们自己实现一个Application类,并维护一个Activity列表,当启动一个Activity时将其增加该列表,当出现未捕获异常时,会逐一finish掉这里的全部Activity。

    public class MyApplication extends Application {

    // Activity列表,用来全然退出应用
    private List<Activity> mActivities = new ArrayList<Activity>();
    // 共享数据
    private Map<String, Object> mAppSharedData = new HashMap<String, Object>();
        
    @Override
    public void onCreate() {
    super.onCreate();
    MyCrashHandler.getInstance(this);
    }

    /**
    * 获取应该共享数据
    * @return
    */
    public Map<String, Object> getAppSharedData() {
    return mAppSharedData;
    }

    /**
    * 加入一个共享Map元素
    * @param map
    */
    public void addSharedData(Map<String, Object> map) {
    mAppSharedData.putAll(map);
    }

    /**
    * 加入一个共享元素
    * @param string
    * @param object
    */
    public void addSharedData(String string, Object object) {
    mAppSharedData.put(string, object);
    }

    /**
    * 获取共享元素值
    * @param string
    * @return
    */
    public Object getValue(String string) {
    return mAppSharedData.get(string);
    }

    /**
    * 当启动一个activity时,加入到该列表中
    * @param activity
    */
    public void addActivity(Activity activity) {
    mActivities.add(activity);
    }

    /**
    * 退出应用
    */
        public void exit() {
        // 循环退出Activity
            try {
                for (Activity activity : mActivities) {
                    if (activity != null)
                        activity.finish();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            // 最后退出虚拟机
                System.exit(0);
            }
        }
        
        @Override
        public void onLowMemory() {
            super.onLowMemory();    
            System.gc();
        }

    }

        上面的mAppSharedData映射表是用于应用的数据共享,不是本文讨论重点。这里重点指出:在MyCrashHandler 中的uncaughtException函数中完毕异常的全部处理。包含停止Service和Activity。在发送重新启动广播之后,退出虚拟机。这里也能够使用以下的代码:

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

  • 相关阅读:
    $dp$模板
    字符串基础
    基础算法

    图论
    山中无甲子,寒尽不知年
    模板集合(持续更新)
    数学基础——同余
    9.19 考试总结
    1-5-17:菲波那契数列
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/7258667.html
Copyright © 2011-2022 走看看