应用退至后台如果进程被系统回收,这个时候我们点击应用如果在应用中没有做相应的处理可能会引发闪退的异常,在谈到如何处理闪退之前我们应该先了解一下什么情况下应用退至后台会被系统干掉了?
进程被杀死有几方面的原因
1.运行内存不足
我们都知道Android系统会给每一个用于进程都分配固定的内存,当我们的应用占用内存超过系统分配的最大内存时就可以引发运存不足会导致的闪退
2.后台运行
有时候我们的应用被退至后台时,因为系统需要回收内存,也有一些系统设置了省点模式等会把后台运行的进程给直接回收掉,当我们点击应用时会唤醒栈顶的Activity,重新走一遍生命周期,如果在这个过程有涉及到一些静态变量、全局变量等未被初始化就被调用则有可能会发生闪退,当然这只是一种情况,也还会有其他的一些情况要看具体的代码。
如何优雅的处理这这种情况?
总结了网上给出的解决方法,大致分类两类
1.onSaveInstanceState和OnRestoreInstanceState来保存和恢复数据
在Activity中利用onSaveInstanceState和OnRestoreInstanceState来保存和恢复数据来确保应用进程被回收后重启能恢复相应的数据,用兴趣的可以百度一下具体的流程,这种方法工作量比较大,因为每个界面的需要保存和恢复的数据都不大一样,所以每个页面都需要进行相应的数据处理。
2.通过静态变量标识判断进程是否回收在重启启动页
当进程被回收时,通过静态变量判断在BaseActivity中重启启动页调用,这样能非常友好的处理闪退带来的不好体验,本篇重点给大家介绍一下通过这种方式如何实现。
实现过程
新建两个状态标识APP_FORCE_KILLED 和APP_NORMAL
class AppStatusConstant {
/*App被回收,初始状态*/
public static final int APP_FORCE_KILLED = 0;
/*正常运行*/
public static final int APP_NORMAL = 1;
}
新建状态管理单例AppStatusManager,通过这个状态管理类去判断当前的进程是正常运行还是已经被系统回收掉了,
public class AppStatusManager {
/*垃圾回收机制会回收掉static关键字占用的内存*/
private static AppStatusManager mInstance = null;
private int appStatus = AppStatusConstant.APP_FORCE_KILLED;
private AppStatusManager() {
}
public static AppStatusManager getInstance() {
if(mInstance==null) {
synchronized (AppStatusManager.class) {
if(mInstance==null)
mInstance = new AppStatusManager();
}
}
return mInstance;
}
public int isAppAlive(Context context, String packageName) {
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> listInfos = activityManager
.getRunningTasks(20);
/*判断程序是否在栈顶*/
if (listInfos.get(0).topActivity.getPackageName().equals(packageName)) {
return ALIVE_STACK_TOP;
} else {
/*判断程序是否在栈里*/
for (ActivityManager.RunningTaskInfo info : listInfos) {
if (info.topActivity.getPackageName().equals(packageName)) {
return ALIVE_STACK_BACKGROUND;
}
}
/*栈里找不到,进程被杀死*/
return ALIVE_STACK_KILLED;
}
}
public void setAppStatus(int appStatus) {
this.appStatus = appStatus;
}
public int getAppStatus() {
return appStatus;
}
}
在启动页onCreate方法中设置当前应用状态为正常运行,注意这个一定要在最早的时候设置,也可以在Application中设置
@Override
protected void onCreate(Bundle savedInstanceState) {
AppStatusManager.getInstance().setAppStatus(AppStatusConstant.APP_NORMAL);
super.onCreate(savedInstanceState);
}
所有的Activity必须基础BaseActivity,在BaseActivity的onCreate方法中判断当前应用的运行状态
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
switch (AppStatusManager.getInstance().getAppStatus())
{
/*应用正常运行*/
case APP_NORMAL:
/*初始化*/
setUpBaseModel();
setUpBaseView();
setUpBaseData(savedInstanceState);
break;
/*应用进程被系统回收*/
case APP_FORCE_KILLED:
restartApp(this);
break;
}
}
APP_NORMAL:这里实现的是初始化的工作,我这里是用了三个抽象的初始化方法,子Activity中去实现这个三个初始化的方法,并在对应的方法中实现相应的初始化业务即可
APP_FORCE_KILLED:进程被回收后,重启会进入这里,这个时候我们需要调用restartApp方法,具体如下
public static void restartApp(Activity activity) {
Intent intent=new Intent(activity, SplashActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);
activity.startActivity(intent);
activity.finish();
}
最后总结一下,这种方式的原理就是利用进程回收后静态变量也会被清除掉,所以我们通过这种方式知道了进程被回收,然后重启启动页并清除栈内的Activity,完美的避免闪退问题