Android应用运行在后台的时候,常常被系统的LowMemoryKiller杀掉,当用户再次点击icon或者从最近的任务列表启动的时候,进程会被重建,而且恢复被杀以前的现场。什么意思呢?假如APP在被杀以前的Activity堆栈是这样的,A<B<C,C位于最上层ide
APP被后台杀死后,APP端进程被销毁了,也就不存在什么Activity了,也就没有什么Activity堆栈,不过AMS的倒是被保留了下来:函数
当用户再次启动APP时候会怎么样呢?这个时候,首先看到其实C,而不是栈底部的A,也就是说每每被杀死后,恢复看到的第一个界面是用户最后见到的那个界面。this
而用户点击返回,看到的就是上一个界面B,其次是Aspa
之因此这样是由于APP端Activity的建立其实都是由AMS管理的,AMS严格维护这APP端Activity对应的ActivityRecord栈,能够看作当前APP的场景,不过,APP端Activity的销毁同AMS端ActivityRecord的销毁并不必定是同步的,最明显的就是后台杀死这种场景。Android为了可以让用户无感知后台杀死,就作了这种恢复逻辑,不过,在开发中,这种逻辑带了的问题确实多种多样,甚至有些产品就不但愿走恢复流程,本文就说说如何避免走恢复流程。结合常见的开发场景,这里分为两种,一种是针对推送唤起APP,一种是针对从最近任务列表唤起APP(或者icon)。code
首先,APP端必须知道当前Activity的启动是否是在走恢复流程,Activity有一个onCreate方法,在ActivityThread新建Activity以后,会回调该函数,若是是从后台杀死恢复来的,回调onCreate的时候会传递一个非空的Bundle savedInstanceState给当前Activity,只要判断这个非空就能知道是不是恢复流程。router
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
复制代码
知道恢复流程以后,如何处理呢?其实很简单,直接吊起闪屏页就能够了,不过这里有一点要注意的是,在启动闪屏页面的时候,必需要设置其IntentFlag:Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK,这样作的理由是为了清理以前的场景,否则以前的ActivityRecord栈仍然保留在ActivityManagerService中,具体实现以下,放在BaseActivity中就能够:cdn
Intent intent = new Intent(this, SplashActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
复制代码
若是不设置会怎么样呢?举个例子,最多见的就是闪屏以后跳转主界面,主界面常常有router逻辑,而且其启动模式通常都是singleTask,处理一些推送,因此其onCreate跟onNewIntent都有相应的处理,若是不设置,在闪屏结束后,在startActivity启动主界面的时候,实际上是先走恢复逻辑,而后走singleTask的onNewIntent逻辑,也就是说,onNewIntent跟onCreate是会同时调用的,也可能就会引起重复处理的逻辑,所以最好清理干净。blog
对于推送消息的处理,其路由器通常放在MainActivity,而且在onCreate跟onNewIntent都有添加,若是APP存活的状况,能够直接跳转目标页面,若是APP被杀,这个时候,但愿先跳转主界面,再跳转目标页面,在效果上来看就是,用户先看到目标页面,点击返回的时候再看到主界面,若是加上闪屏,但愿达到的效果是先看到闪屏、点击返回看到目标页,再点击返回看到主页面。若是简单划分一下推送场景,能够看作一下三种进程
其实后面两种彻底能够看作一种,这个时候,都是要先start MainActivity,而后让MainActivity在其OnCreate中经过startActivityForResult启动SplashActivity,SplashActivity返回后,在start TargetActivity。下面的讨论都是针对后面两种,须要作的有两件事路由
如何判断呢,后面两种场景其实只须要判断是否有Activity存活便可,也就是查查APP的topActivity是否为null,注意不要去向AMS查询,而是在本地进程中查询,能够经过反射查询ActivityThread的mActivities,也能够根据本身维护的Activity堆栈来判断,判断没有存活Activity的前提下,就跳转主页面去路由
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setDate(跳转的Uri scheme)
startActivity(intent);
复制代码
在MainActivity的路由中,须要准确区分是不是推送跳转进来的,若是不是推送跳转进来,就不须要什么特殊处理,若是是推送跳转进来必定会携带跳转scheme数据,根据是否携带数据作区分便可,看一下MainActivity的代码:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Uri uri= getIntent().getData();
<!--只有在intent被设置了跳转数据的时候才去跳转,通常是推送就来,若是冷启动,是没有数据的-->
if(uri!=null){
SplashActivity.startActivityForResult(this,JUMP_TO_TARGET)
}
}
<!--Intent.FLAG_ACTIVITY_CLEAR_TASK保证了onNewIntent被调用的时候,进程必定是正常活着的-->
@Override
protected void onNewIntent(Intent intent) {
Uri uri= intent.getData();
intent.setData(null);
router(uri);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==JUMP_TO_TARGET && requestCode == RESULT_OK){
router(getIntent().getData());
getIntent().setData(null);
}
}
private void router(Uri uri) {
}
复制代码
经过上面两部分的处理,基本可以知足APP“死亡”的状况下,先跳转闪屏的需求。
做者:看书的小蜗牛 原文连接:被后台杀死后,Android应用如何从新走闪屏逻辑
仅供参考,欢迎指正