自己定义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());
自己定义Application的未捕获异常处理的更多相关文章
- Java & Android未捕获异常处理机制
一.背景 无论是Java还是Android项目,往往都会用到多线程.不管是主线程还是子线程,在运行过程中,都有可能出现未捕获异常.未捕获异常中含有详细的异常信息堆栈,可以很方便的去帮助我们排查问题. ...
- Android 之 应用未捕获异常处理
最近开发一款低功耗蓝牙通讯的 Android 应用,安装使用时多次出现“ 抱歉,xxx已停止 ”.现在安装Android系统的手机版本和设备千差万别,在模拟器上运行良好的程序安装到某款手机上说不定就出 ...
- Java线程未捕获异常处理 UncaughtExceptionHandler
当一个线程在执行过程中抛出了异常,并且没有进行try..catch,那么这个线程就会终止运行.在Thread类中,提供了两个可以设置线程未捕获异常的全局处理器,我们可以在处理器里做一些工作,例如将异常 ...
- PHP 面向对象编程和设计模式 (4/5) - 异常的定义、扩展及捕获
PHP高级程序设计 学习笔记 2014.06.12 异常经常被用来处理一些在程序正常执行中遇到的各种类型的错误.比如做数据库链接时,你就要处理数据库连接失败的情况.使用异常可以提高我们程序的容错特性, ...
- Android中使用UncaughtExceptionHandler来处理未捕获的异常
原文在sparkyuan.me上.转载注明出处:http://sparkyuan.github.io/2016/03/28/使用UncaughtExceptionHandler来处理未捕获的异常/ 全 ...
- Dream------scala--函数定义、流程控制、异常处理
Dream------scala--函数定义.流程控制.异常处理 一.函数的定义 1.新建工程
- c#处理未捕获的异常(UnhandledException)
处理未捕获的异常,放在program类的Main函数下 1.UnhandledException 作用:接收未捕获到的异常 例: static void Main(string[] args) { A ...
- Scala深入浅出实战经典-----002Scala函数定义、流程控制、异常处理入门实战
002-Scala函数定义.流程控制.异常处理入门实战 Scala函数定义 语句结束无分号 定义无参函数 def 函数名称(参数名称:参数类型)[:Unit=]{ 函数体 } 老师的代码 我的实际代码 ...
- VS2010 F5调试时出现:“ 尝试运行项目时出错:未捕获通过反射调用的方法引发的异常”解决
VS2010 F5调试时出现 尝试运行项目时出错:未捕获通过反射调用的方法引发的异常 两个解决方法:1) 打开项目属性,选择调试选项卡,将“启用非托管代码调试”一项钩上.2) 打开项目属性,选择调试选 ...
随机推荐
- Ubuntu16.04 -- 后台进程Nohup
nohup用于使程序在用户退出登陆.关闭终端之后仍能继续运行 用法: nohup your_command & #(符号&使程序在后台运行) exit #(退出nohup模式) 启动后 ...
- django静态html中做动态变化
在搭建网站中经常有筛选分类的需求 在django中为了简便,我们经常将某些相同部分的内容取出来单独存放形成一个base模板,其他的template继承这个base就可以使用其中的内容 但是这些相同的部 ...
- http://www.cnblogs.com/dolphin0520/p/3949310.html
http://www.cnblogs.com/dolphin0520/p/3949310.html
- zabbix自定义触发器
zabbix中监控项仅负责收集数据,而通常收集数据的目的还包括在某指标对应的数据超出合理范围时给相关人员发送告警信息,"触发器"正式 用于为监控项所收集的数据定义阈值,每一个触发器 ...
- 2017.7.21 Linux中ELK服务后台运行方式
通过 2017.7.18 linux下ELK环境搭建 搭建好服务于之后,一旦按下Ctrl+C或者退出登录会话,服务的进程就随之停止了.要长期在后台运行此程序,有几种方式: 1 nohup 输入Ctrl ...
- 联想T470设置U盘启动
联想T470设置U盘启动 学习了:http://www.udaxia.com/upqd/10092.html # F12 in Enter in USB HDD 如果不行: App Menu > ...
- 自己如何正确获取MYSQL的ADO连接字符串
1.下载安装MYSQL的ODBC数据库驱动程序(mysql-connector-odbc-5.3.4-win32.msi或者mysql-connector-odbc-5.3.4-winx64.msi) ...
- 《Android源代码设计模式解析与实战》读书笔记
1.定义 将对象组合成树形结构以表示"部分-总体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性. 2.使用场景 (1)表示对象的部分-总体层次结构时. (2)从一个总体 ...
- JavaWeb Session详解
代码地址如下:http://www.demodashi.com/demo/12756.html 记得把这几点描述好咯:代码实现过程 + 项目文件结构截图 + ## Session的由来 上一篇博文介绍 ...
- 如果你报createSQLQuery is not valid without active transaction,请看这里
原文:https://blog.csdn.net/yinjian520/article/details/8666695 很多时候我们使用hibernate的session时,都是让session在某一 ...