0
点赞
收藏
分享

微信扫一扫

如何让你的app在后台被干掉后优雅的启动

云卷云舒xj 2022-04-27 阅读 84

就不多介绍这个生命周期了,相信都熟悉不过了,有想了解的自行Google或者百度吧。

重点

首先,我们得知道,为什么程序会在后台被干掉的?我们又没有手动关闭程序。

app在后台被强杀,是在内存不足的情况下被强制释放了,也有一些恶心的rom会强制杀掉那些后台进程以释放缓存以提高所谓的用户体验。(注:当你的代码写得混乱、冗余,而且非常消耗内存的时候,那你的app在后台运行时将会比较容易被系统给干掉的,所以从现在开始要约束自己要养成良好的编码习惯和注意内存泄漏的问题)

我们都觉得android rom很恶心,但同时还是用些更恶心的手法去绕开这些瓶颈。乱,是因为在最上层没有一个很好的约束,这也是开源的弊端。anyway。我们还是得想破脑袋来解决这些问题,否则饭碗就没了。

我们现在来重现这个熟悉的一幕:

假设:App A -> B -> C

在C activity中点Home键后台运行,打开ddms,选中该App进程,强杀。

然后从“最近打开的应用”中选中该App,回到的界面是C activity,假设App中没有静态变量,这个时候是不会crash的,点击返回到B,这个时候也只是短暂白屏后显示B界面。但如果B中有引用静态变量,并想要获取静态变量中的某个值时,就NullPointer了。

以上复现的流程就几个点,我们展开说下:

当应用被强杀,整个App进程都是被杀掉了,所有变量全都被清空了。包括Application实例。更别提那些静态变量了。

虽然变量被清空了,但Android给了一些补救措施。activity栈没有被清空,也就是说A -> B -> C这个栈还保存了,只是ABC这几个activity实例没有了。所以回到App时,显示的还是C页面。另外当activity被强杀时,系统会调用onSaveInstance去让你保存一些变量,但我个人觉得面对海量的静态变量,这个根本不够用。返回到B会白屏,是因为B要重绘,重走onCreate流程,渲染上需要点时间,所以会白屏了。

大概是以上这些点。如果App中没有静态变量的引用,那就不用出现NullPointer这个crash,也就不需要解决。一旦你有静态变量,或者有些Application的全局变量,那就很危险了。比如登录状态,user profile等等。这些值都是空了。

肯定会有人说,这没关系啊,所有的静态变量都改到单例去不就好了吗?然后附加上一些持久化cache,空了再取缓存就ok了嘛。嗯,这肯定也是一个办法,但是这样的束手束脚对开发来说也是痛苦,至少需要多50%的编码时间才能全部cover。另外,还有那么多帮你挖坑的队友,难省心啊。

既然App都被强杀了,干嘛不重新走第一次启动的流程呢,别让App回到D而是启动A,这样所有的变量都是按正常的流程去初始化 《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》无偿开源 徽信搜索公众号【编程进阶路】 ,也就不会空指针了,对吧?有人说这方案用户体验一点都不好呀。但哪有十全十美的事呢,是重走流程好,还是一点一个NullPointer好?好好去沟通,相信产品也不会为难你的。当然你也可以拿来举例,iOS在最近打开的应用里杀了某个App,重新点击那个App,还是会重走流程的啊。

如果你说用户已经打开了C界面,所以重新打开的是是恢复到C界面,这样的用户体验会更好啊,如果你是这样认为的,那你很多时间都是在防止恢复的时候不让你的app crash了,与其这样,还不如让整个app重新走整个流程呢,这样更省时间,而且这样也不用担心随时都会崩溃的情况,难道这样的用户体验不会更好吗?

那且想想如何让它不回到C而是重走流程呢?也就是说中断C的初始化而回到A,并且按back键,不会回到C,B。考虑一下。

我们先实例化这个场景吧。
A为App的启动页
B为首页
C为二级页面

把首页launchMode设置为singleTask,具体为什么上面介绍activity的启动模式的时候已经介绍了singleTask的作用了。

在BaseActivity中onCreate中判断App是否被强杀,强杀就不往下走,直接重走App流程。

首页起一个承接或者中转的作用,所有跨级跳转都需要通过首页来完成。

具体实现

AppStatusConstant

public static final intSTATUS_FORCE_KILLED = -1;//应用放在后台被强杀了
public static final intSTATUS_NORMAL = 2; //APP正常态//intent到MainActivity区分跳转目的
public static finalStringKEY_HOME_ACTION = “key_home_action”;//返回到主页面
public static final intACTION_BACK_TO_HOME = 0;//默认值
public static final intACTION_RESTART_APP = 1;//被强杀

AppStatusManager

public intappStatus= AppStatusConstant.STATUS_FORCE_KILLED; //APP状态初始值为没启动不在前台状态
public staticAppStatusManagerappStatusManager;
privateAppStatusManager() {
}
public staticAppStatusManagergetInstance() {
if(appStatusManager==null{
appStatusManager=newAppStatusManager();
}
returnappStatusManager;
}
public intgetAppStatus() {
returnappStatus;
}
public voidsetAppStatus(intappStatus) {
this.appStatus= appStatus;
}

BaseActivity(大致内容)

switch(AppStatusManager.getInstance().getAppStatus()) {
caseAppStatusConstant.STATUS_FORCE_KILLED:
restartApp();
break;
caseAppStatusConstant.STATUS_NORMAL:
setUpViewAndData();
break;
}
protected abstract voidsetUpViewAndData();
protected voidrestartApp() {
Intent intent =newIntent(this,MainActivity.class);
intent.putExtra(AppStatusConstant.KEY_HOME_ACTION,AppStatusConstant.ACTION_RESTART_APP);
startActivity(intent);
}

每一个继承于父activity的都不要在oncreat中实现界面初始化和数据的初始化,因为如果被杀死之后,回来会走一次正常的生命流程的。

StartPageActivity配置(在oncreat()方法配置,并且在super()前):

举报

相关推荐

0 条评论