近期由于工作原因。进行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());

自己定义Application的未捕获异常处理的更多相关文章

  1. Java & Android未捕获异常处理机制

    一.背景 无论是Java还是Android项目,往往都会用到多线程.不管是主线程还是子线程,在运行过程中,都有可能出现未捕获异常.未捕获异常中含有详细的异常信息堆栈,可以很方便的去帮助我们排查问题. ...

  2. Android 之 应用未捕获异常处理

    最近开发一款低功耗蓝牙通讯的 Android 应用,安装使用时多次出现“ 抱歉,xxx已停止 ”.现在安装Android系统的手机版本和设备千差万别,在模拟器上运行良好的程序安装到某款手机上说不定就出 ...

  3. Java线程未捕获异常处理 UncaughtExceptionHandler

    当一个线程在执行过程中抛出了异常,并且没有进行try..catch,那么这个线程就会终止运行.在Thread类中,提供了两个可以设置线程未捕获异常的全局处理器,我们可以在处理器里做一些工作,例如将异常 ...

  4. PHP 面向对象编程和设计模式 (4/5) - 异常的定义、扩展及捕获

    PHP高级程序设计 学习笔记 2014.06.12 异常经常被用来处理一些在程序正常执行中遇到的各种类型的错误.比如做数据库链接时,你就要处理数据库连接失败的情况.使用异常可以提高我们程序的容错特性, ...

  5. Android中使用UncaughtExceptionHandler来处理未捕获的异常

    原文在sparkyuan.me上.转载注明出处:http://sparkyuan.github.io/2016/03/28/使用UncaughtExceptionHandler来处理未捕获的异常/ 全 ...

  6. Dream------scala--函数定义、流程控制、异常处理

    Dream------scala--函数定义.流程控制.异常处理 一.函数的定义 1.新建工程

  7. c#处理未捕获的异常(UnhandledException)

    处理未捕获的异常,放在program类的Main函数下 1.UnhandledException 作用:接收未捕获到的异常 例: static void Main(string[] args) { A ...

  8. Scala深入浅出实战经典-----002Scala函数定义、流程控制、异常处理入门实战

    002-Scala函数定义.流程控制.异常处理入门实战 Scala函数定义 语句结束无分号 定义无参函数 def 函数名称(参数名称:参数类型)[:Unit=]{ 函数体 } 老师的代码 我的实际代码 ...

  9. VS2010 F5调试时出现:“ 尝试运行项目时出错:未捕获通过反射调用的方法引发的异常”解决

    VS2010 F5调试时出现 尝试运行项目时出错:未捕获通过反射调用的方法引发的异常 两个解决方法:1) 打开项目属性,选择调试选项卡,将“启用非托管代码调试”一项钩上.2) 打开项目属性,选择调试选 ...

随机推荐

  1. git只拉取github部分代码的方法

    需求:github某个项目所有代码太大,有600+M,甚至更大:只需要拉取部分代码,一是可以降低网络消耗,二是可以降低磁盘占用 分析了下空间占用情况:发现每个项目下的.git/objects/pack ...

  2. Struts2实现登录权限访问控制

    目录: Ⅰ 条件 Ⅱ 目的 Ⅲ 分析 Ⅳ 实现 Ⅴ 具体代码实现 ------------------------------------------------------------------- ...

  3. Hive删除分区

    Hive删除分区语句: alter table table_name drop if exists partition(dt=30301111)

  4. HUNAN Interesting Integers(爆力枚举)

    Undoubtedly you know of the Fibonacci numbers. Starting with F1 = 1 and F2 = 1, every next number is ...

  5. 双人对战的球类游戏ios源代码项目

    双人对战的球类游戏源代码,这个是一款双人对战的ios球类游戏源代码.游戏的源代码也比較具体的,我们在屏幕上下看到各有一个球门.内有一球,两边通过控制轮盘使球进入对方的球门的.事实上玩法也非常easy的 ...

  6. python makestrans translate

    """ 1. makestrans()用法 语法: str.maketrans(intab, outtab]); Python maketrans() 方法用于创建字符映 ...

  7. Android学习(十四) Service组件

    一.定义 运行在后台,没有页面,不可见.优先级高于Activity,当系统内存不足时,会先释放一些Activity.注意,Service同样是运行在主线程中,不能做一些耗时操作.如果一定要做一些耗时的 ...

  8. hdu 5365 Run(BC 50 B题)(求四边形的个数)

    本来准备睡觉.结果还是忍不住想把它A了.由于已经看了题解了, 题意:就是给你一些坐标.都是整数,求一些正多边形的数目,官方题讲解是地球人都知道整数坐标构不成正三角形.正五边形和正六边形的... 然而我 ...

  9. 【Shell】Read命令

    read命令从键盘读取变量的值,通常用在shell脚本与用户进行交互的场合.该命令可以一次性读取多个变量的值,变量的输入和输出需要使用空格隔开.在read命令后面,如果没有指定变量名,读取的数据将被自 ...

  10. SQL Server变量赋值的方法

    SQL Server变量赋值我们经常会遇到,下面就为您介绍SQL Server变量赋值的两种方法,希望可以对您学习SQL Server变量赋值有所帮助. SQL Server中对已经定义的SQL Se ...