最近应项目需求,需要实现在APP遇到内部bug闪退时,禁止自启动回到闪退界面
经测试,在 Android 的 API 21 ( Android 5.0 ) 以下,Crash 会直接退出应用,但是在 API 21 ( Android 5.0 ) 以上,系统会遵循以下原则进行重启:
- 包含 Service,如果应用 Crash 的时候,运行着Service,那么系统会重新启动 Service。
- 不包含 Service,只有一个 Activity,那么系统不会重新启动该 Activity。
- 不包含 Service,但当前堆栈中存在两个 Activity:Act1 -> Act2,如果 Act2 发生了 Crash ,那么系统会重启 Act1。
- 不包含 Service,但是当前堆栈中存在三个 Activity:Act1 -> Act2 -> Act3,如果 Act3 崩溃,那么系统会重启 Act2,并且 Act1 依然存在,即可以从重启的 Act2 回到 Act1。
看了上述解释,我们终于知道应用在什么种情况下才会重启。
面对这样的问题,我们提供两种解决思路,一是允许应用自动重启,并在重启时恢复应用在崩溃前的运行状态。二是禁止应用自动重启,而是让用户在应用发生崩溃后自己手动重启应用。
具体解决办法如下:
1.首选创建一个CrashHanler类
package com.pdl.mallpos.util;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import com.pdl.mallpos.PDLApplication;
public class CrashHandler implements Thread.UncaughtExceptionHandler {
public static CrashHandler mAppCrashHandler;
private Thread.UncaughtExceptionHandler mDefaultHandler;
private PDLApplication mAppContext;
public void initCrashHandler(PDLApplication application) {
this.mAppContext = application;
// 获取系统默认的UncaughtException处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
public static CrashHandler getInstance() {
if (mAppCrashHandler == null) {
mAppCrashHandler = new CrashHandler();
}
return mAppCrashHandler;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
System.gc();
}
}
/**
* 错误处理,收集错误信息 发送错误报告等操作均在此完成.
* @param ex
* @return true:如果处理了该异常信息;否则返回false.
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
// 自定义处理错误信息
return true;
}
}
2.在应用Application的onCreate()接口中调用,具体调用如下:
CrashHandler.getInstance().initCrashHandler(this);
此时可能查阅文档的小伙伴发现很多文档写到这里就结束了,但是执行后发现闪退后仍然会重启到闪退页面,别急,我们需要知道这是什么原因造成的。
退出栈内所有的Acitvity
如果应用在发生崩溃时,回退栈内依然存在没有退出的Activity,即使调用了System.exit(0)
方法,应用依然会自动重启。因此我们就需要在应用退出之前,先清除栈内所有的Activity。
3.在Application中创建一个activityList,用来存储所有栈内的Activity,很简单,方法如下
public static List<Activity> activityList = new ArrayList<Activity>();
4.创建一个BaseActivity,让所有的Activity都继承BaseActivity,并在Activity中如下接口执行添加和删除
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(!PDLApplication.activityList.contains(this)){
PDLApplication.activityList.add(this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(PDLApplication.activityList.contains(this)){
PDLApplication.activityList.remove(this);
}
}
5.在刚才的CrashHanler中执行如果Application中的activityList不为空,则手动关闭所有Activity
package com.pdl.mallpos.util;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import com.pdl.mallpos.PDLApplication;
public class CrashHandler implements Thread.UncaughtExceptionHandler {
public static CrashHandler mAppCrashHandler;
private Thread.UncaughtExceptionHandler mDefaultHandler;
private PDLApplication mAppContext;
public void initCrashHandler(PDLApplication application) {
this.mAppContext = application;
// 获取系统默认的UncaughtException处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
public static CrashHandler getInstance() {
if (mAppCrashHandler == null) {
mAppCrashHandler = new CrashHandler();
}
return mAppCrashHandler;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
if(PDLApplication.activityList.size()>0){
for(int i=0;i<PDLApplication.activityList.size();i++){
Activity activity = PDLApplication.activityList.get(i);
if(activity!=null){
activity.finish();
}
}
}
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
System.gc();
}
}
/**
* 错误处理,收集错误信息 发送错误报告等操作均在此完成.
* @param ex
* @return true:如果处理了该异常信息;否则返回false.
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
// 自定义处理错误信息
return true;
}
}
好了大功告成,接下来小伙伴们试一下吧。