作为一名Android开发师,肯定在处理用户的体验上下一定的功夫。有这么一个场景,在用户用着你开发的app的时候,突然某个聊天工具来消息了,切换到聊天工具后长时间停留,并且可能做了一些你不知道的操作,比如看视频阿,刷刷消息圈什么的。一般这种情况下都很容易出现手机内存不足的情况,内存不足就会可能被干掉。这种时候用户切换到app准备继续操作时,如果开发师处理不好,就会引起崩溃的情况,肯定会出现返回的时候一瞬间的白屏,对于用户体验的来说,非常不好。 
开始

首先要介绍下Android中activity的四种启动模式(就当作复习一下旧知识吧,资料来源于网络总结):

Standard:是默认的也是标准的Task模式,在没有其他因素的影响下,使用此模式的Activity,会构造一个Activity的实例,加入到调用者的Task栈中去,对于使用频度一般开销一般什么都一般的Activity而言,standard模式无疑是最合适的,因为它逻辑简单条理清晰,所以是默认的选择。

singleTop:基本上于standard一致,仅在请求的Activity正好位于栈顶时,有所区别。此时,配置成singleTop的Activity,不再会构造新的实例加入到Task栈中,而是将新来的Intent发送到栈顶Activity中,栈顶的Activity可以通过重载onNewIntent来处理新的Intent(当然,也可以无视...)。这个模式,降低了位于栈顶时的一些重复开销,更避免了一些奇异的行为(想象一下,如果在栈顶连续几个都是同样的Activity,再一级级退出的时候,这是怎么样的用户体验...),很适合一些会有更新的列表Activity展示。一个活生生的实例是,在Android默认提供的应用中,浏览器(Browser)的书签Activity(BrowserBookmarkPage),就用的是singleTop。

singleTask:配置了这个属性的activity,最多仅有一个实例存在,而且,它在根的task中,在之后的被杀死重启的过程中我们会利用到这个配置,也就是我们的主界面MainActivity。

singleInstance:跟上面的singleTask基本上是一样的,但是,singleInstance的Activity,是它所在栈中仅有的一个Activity,如果涉及到的其他Activity,都移交到其他Task中进行,在实际开发中这个是用得比较少的。

这个是activity的生命周期:

就不多介绍这个生命周期了,相信都熟悉不过了,有想了解的自行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,这样所有的变量都是按正常的流程去初始化,也就不会空指针了,对吧?有人说这方案用户体验一点都不好呀。但哪有十全十美的事呢,是重走流程好,还是一点一个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流程。

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

再给个提示,以上场景的解决方案也可以用于解决其它相关问题:
在任意页面退出App
在任意页面返回到首页
其实最重要的知识点就是launchMode

具体实现

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()前):

AppStatusManager.getInstance().setAppStatus(AppStatusConstant.STATUS_NORMAL);//进入应用初始化设置成未登录状态

MainActivity(配置了singleTask的主界面)

@Override
protected voidrestartApp() {Toast.makeText(getApplicationContext(),"应用被回收重启",Toast.LENGTH_LONG).show();startActivity(newIntent(this,StartPageActivity.class));finish();
}
@Override
protected voidonNewIntent(Intent intent) {super.onNewIntent(intent);intaction = intent.getIntExtra(AppStatusConstant.KEY_HOME_ACTION,AppStatusConstant.ACTION_BACK_TO_HOME);switch(action) {caseAppStatusConstant.ACTION_RESTART_APP:restartApp();break;}
}

当应用打开的时候,启动StartPageActivity,然后设置app的status为normal状态,记住,一定要设置,因为默认的是被杀死的状态的。

当应用被杀死之后,所有数据都会被回收,所以之前设置的app status也会置于默认状态,即杀死状态,所以再次打开app的时候,status为杀死状态,就会走重启的流程,这里为什么要先跳转到MainActivity呢?就是因为MainActivity配置为了Sing了Task,当跳转到这个界面时,MainActivity就会置于Activity Task的最上层,其他的Activity将会被默认销毁掉,利用这种技巧去销毁其他的Activity,最后才是重新启动StartPageActivity。整个流程就是这样了。

大致的实现就如上所述了,我所倡导的宗旨就是花最少的时间,写最好的代码,实现最好的体验!之前也参考过很多网上大神们的实现方式,但是我觉得以上实现的应该是比较完整的一种了。

此文思路借鉴于Me豪。

如何让你的app在后台被干掉后优雅的启动。相关推荐

  1. App在后台被杀死后重启-重进首页方法

    感谢这位哥的思路. 这个问题很常见,基本所有app都会遇到这个问题.但是很多开发者都没有处理. 问题的起因:我的app在进入后台后一段时间,可能被系统干掉了,然后通过多任务键,或者图标再点进去操作,出 ...

  2. android 后台运行清理,【Android】App在后台被清理后的终极应对手段——重启应用...

    检测App是否在后台期间被销毁 添加一个null值的Object标记对象到Application,并在App运行期间赋值一个非null任意对象,如果App在后台期间被OS销毁,则该对象会被清空(适用于 ...

  3. APP在后台被系统回收后,如何重新启动

    问题: app运行在后台,android系统会在内存不够用的时候,回收app,如果app中有全局的变量,那么再次打开app可能会出现崩溃的情况. 示例: 示例源码 public class MyApp ...

  4. 旅游订票订酒店团购(APP,JAVA后台管理,MYSQL)

    旅游订票订酒店团购(APP,JAVA后台管理,MYSQL)(毕业论文近11000字以上,共39页, 包含程序代码,MySql数据库,数据库脚本) [功能描述] 旅游订票订酒店团购(APP,JAVA后台 ...

  5. app与后台通信完整流程

    前言: 接着补充app后台(也叫服务端开发)的基础知识.基础要夯实,不然哪来的万张高楼? 正文: 问1:整个前台后台交互的流程是个什么样子? 答:基于http协议的app前后台交互包含以下几个步骤: ...

  6. app切换到后台一分钟后锁定,需要输入手势密码才能打开(程序锁)

    #app切换到后台一分钟后锁定,需要输入手势密码才能打开(程序锁) 解锁规则: 未设置解锁密码,则什么都不用输入即可进入应用 1分钟内再次回到应用,无需输入密码.手势密码等即可进入 超过1分钟后回到应 ...

  7. android app 的后台代码,包括后台的Android美食APP项目开源代码

    项目简介 小食光定位为一款集美食,社交,LBS服务于一体的美食推荐APP.为你发现周边美食的同时提供一个吃货分享的平台. APP截图 功能模块 美食推荐 :提供基础的美食信息查询: 商家推荐 : 基于 ...

  8. APP在后台被系统杀死的六种主要原因

    主要介绍在APP在后台被系统杀死的六种主要原因,源自WWDC视频, 并且告诉你怎么使用MetricKit框架去发现和减少程序被强制杀死的概率:怎么防止崩溃:怎么使用后台机制,怎么找到潜在的问题并采取行 ...

  9. iOS保持App真后台运行

    https://www.jianshu.com/p/d466f2da0d33 在我看来,苹果系统与安卓系统最直观的区别就是后台处理方式了吧,安卓手机一旦开启了很多app放到后台,即使前台什么也不做,就 ...

  10. 基于MUI的驾考宝典APP及后台管理系统

    目录 基于MUI的驾考宝典APP及后台管理系统 前端APP 技术栈 开发工具 GitHub地址 后端API及后台管理系统 技术栈 开发工具 GitHub地址 运行效果 APP 后台 基于MUI的驾考宝 ...

最新文章

  1. 数据分析之Pandas缺失数据处理
  2. Gulp 自动化的项目构建工具
  3. 每日一皮:男人有三宝「胡子、发型和肌肉」...
  4. javascript调试工具
  5. python mpl_toolkits.mplot3d.axes3d.Axes3D()使用 介绍
  6. Eclipse6里面SSH整合说明
  7. 系统集成资质培训 - 在线答疑(17:00更新)
  8. 如何查看光驱硬盘托架的尺寸_如何确定光驱位的硬盘托架的大小尺寸和接口
  9. 规格选择_日常使用的拉杆箱脚轮选择哪种规格最合适?
  10. 【转】DICOM医学图像读取涉及到的医学坐标体系
  11. java Trie实现英文单词查找树 搜索自动提示
  12. camvid数据集介绍_语义分割的数据集
  13. 获取数据库值,再在其值上做修改
  14. 一天一工程总结系列-7.2
  15. 浏览器工作原理和实践
  16. 新版眼保健操图解(转)
  17. 【小月电子】ALTERA FPGA开发板系统学习教程-LESSON8 LCD1602液晶显示
  18. 1、u3d 下载、安装
  19. element 复杂表格,表格合并
  20. uos应用_终极指标(UOS)应用法则

热门文章

  1. 最新架构amd服务器cpu,2015年或新变化?AMD将专注高性能架构
  2. excel----分组后统计
  3. 又见猛犸象:基因剪刀重新定制生命
  4. 10000以内的质数表
  5. keras深度训练4:GPU设置
  6. 专利分析的方法和流程
  7. 西安电子科技大学和东北大学计算机,西安电子科技大学和东北大学比较,哪个好,特别是计算机软件方面...
  8. 详细Ubuntu系统修改默认软件下载源
  9. vivo手机支持html,vivo5G手机如何设置5G?教你开启SA模式
  10. css 剪辑图片_[译]用CSS剪切圆形图片