自定义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());

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 04:41:08

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

自己定义Application的未捕获异常处理

近期由于工作原因.进行Android应用开发时发现应用在出现类似空指针等异常时,抛出未被捕获的异常.Android系统有默认的未捕获异常处理器,默认行为是结束对应的线程,但并不会直接退出程序,并且在应用还有后台Service时.服务还一直在执行,假设service在请求网络时还会抛出一些异常信息,并且在未全然退出的应用中再次使用还会进一步导致异常,这样对于用户体验来说实在不好. 因此,须要在应用无论什么情况下出现异常后应该直接退出应用,然后重新启动应用.网上搜了非常多资料.非常多都不能非常好解决

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

原文在sparkyuan.me上,转载注明出处:http://sparkyuan.github.io/2016/03/28/使用UncaughtExceptionHandler来处理未捕获的异常/ 所有的App都会发生crash,本文讲解的是如何采集crash信息以供后续开发处理这类问题. 基本思路 当crash发生时,系统会调用UncaughtExceptionHandler的uncaughtException方法,我们可以在这个方法中捕获异常信息,把异常信息存到SD卡中,在合适的时候通过网络

编写高质量代码改善C#程序的157个建议——建议65:总是处理未捕获的异常

建议65:总是处理未捕获的异常 处理为捕获的异常是每个应用程序具备的基本功能,C#在APPDomain提供了UnhandledException事件来接收未捕获到的异常的通知.常见的应用如下: static void Main(string[] args) { AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); } s

【Android 个人理解(七)】用ContentValues和自定义Application处理数据

我当时面临的需求是 1.核心算法数据和UI的交互,2.多个数组数据的封装,3.不确定的数组数据转化到表格形式. 就于以上需求,我采用自定义的Application储存和传递全局的数据,采用ContentValues的key-value转化和储存数组数据,然后通过遍历ContentValues的key将对应的值填入对应的表格. 大体的步骤如下: 1.从UI界面获取数据,通过循环填充成数组. // 得到三个初始化编号的值 private void SetValuesAtNewTab(View new

朝花夕拾-android 自定义application 管理activity的生命周期

为了安全退出多个已创建的activity? 可以自定义application:myapplication. 增加一个list成员保存,一些关键的已创建的activity实例: 1 private List<Activity> activityList = new LinkedList<Activity>(); 2 3 // 保存 所有activity的this 4 public void addActivity(Activity activity) { 5 activityList

Android编程入门--自定义Application

Android系统自动会为每个程序运行时创建一个Application类的对象且只创建一个 参考博客:Android 当中 application的使用 参考文章:全局对象Application的使用,以及如何在任何地方得到Application全局对象 参考文章:Android基础之自定义Application 自定义 public class AppContext extends Application 单例模式 private static AppContext app; /** * 单例

错误-终止应用程序由于未捕获的异常的nsinvalidargumentexception’,原因:“[:]:未知的UIView setImage选择器送到实例0x8d78d20”

1 UIImage *image = [UIImage imageNamed:tempAppInfo.icon]; 2 UIImageView *appIcon = (UIImageView *) [appView viewWithTag:0]; 3 appIcon.image = image; 每次执行到第三句时就报错: 更改办法: 把UIImageView的tag改掉不要用0. 原因分析:?. 错误-终止应用程序由于未捕获的异常的nsinvalidargumentexception',原因:

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

S2010 F5调试时出现 尝试运行项目时出错:未捕获通过反射调用的方法引发的异常 两个解决方法:1) 打开项目属性,选择调试选项卡,将“启用非托管代码调试”一项钩上.2) 打开项目属性,选择调试选项卡,将“启用Visual Studio宿主进程“一项钩掉. 原文地址:https://www.cnblogs.com/gisoracle/p/9690123.html

解析服务器实时查询错误:未捕获TypeError:无法读取属性的onNext定义

服务器是完全设置但在客户端代码 let query = new Parse.Query('Notification');let subscription = query.subscribe();subscription.on('open', () => {console.log('subscription opened');});抛出错误: 未捕获TypeError:无法读取属性"onNext"定义的订阅. 第3894行 第3894行 key: 'pushData', value