activity的生命周期
正常情况下activity的生命周期
如下图所示:
整个生命周期,onCreate 和onDestroy,onStart和onStop,onResume和onPause都是一一配对的。
问题
当前Activity为A,用户打开新的ActivityB,B的onResume和A的onPause方法那个先执行?
当启动一个新的activity是,旧的activity的onPause会先执行,然后启动新的activity。具体执行流程:A.onPause——B.oncCreate——B.onStart——B.onResume——A.onStop。
异常情况下activity生命周期
activity除了随着用户操作调用生命周期的方法外,还会有异常情况。比如系统配置发生变化和系统内存不足时的异常情况。
1.系统配置发生变化导致activity被杀死和创建
当系统配置发生变化后,activity可能会被销毁,系统会调用onSaveInstanceState
保存当前activity的状态,onSaveInstanceState
一定发生在onStop方法之前,和onPause方法没有关系,可能在前可能在后发生。当activity重新创建的时候,系统会调用onRestoreInstanceState
或onCreate
方法获取保存的数据然后可以恢复。当然onRestoreInstanceState的调用时机也一定在onStart之后。activity委托window自动已经帮我们做了一些恢复工作,可以查看每个view的onSaveInstanceState和onRestoreInstanceState方法的具体实现。onSaveInstanceState只会在activity即将被销毁并且有机会重新显示的情况才会调用。比如屏幕旋转的异常销毁,会创建新的activity显示。普通的正常销毁并不会调用onSaveInstanceState方法。
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
onRestoreInstanceState
或onCreate的
区别
onRestoreInstanceState一旦被调用,参数Bundle savedInstanceState肯定是有值的,不用额外判空。而onCreate正常启动时,参数Bundle savedInstanceState肯定是null,必须做额外的判断才能恢复数据。所以说用onRestoreInstanceState简单一些。
系统配置发生变化时,让activity不重新创建
给activity设置configChanges
属性,比如设置屏幕旋转时,不重新创建activity就设置
android:configChanges="orientation"
想设置多个值用“|”隔开。常用的有locale、orientation、keyboardHidden等其他自行查看。
这种情况下不会重启activity,也不会调用onSaveInstanceState和onRestoreInstanceState方法存储恢复数据,取而代之的调用了onConfigurationChanged方法
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
2.内存不足导致activity被杀死
系统会根据activity优先级杀死目标activity来腾出内存空间,和上面情况1一样的数据存储和恢复。
activity的启动模式
activity的四种launchmode
1.standard:标准模式
系统默认模式,只要启动一个activity就会创建一个activity实例,不管这个实例存不存在,这种模式下,谁启动了该模式的Activity,该Activity就属于启动它的Activity的任务栈中。这个Activity它的onCreate(),onStart(),onResume()方法都会被调用。
2.singleTop:栈顶复用模式
如果新的activity已经位于栈顶,那么这个Activity不会被重写创建,同时它的onNewIntent()
方法会被调用,通过此方法的参数我们可以去除当前请求的信息。如果栈顶不存在该Activity的实例,则情况与standard模式相同。需要注意的是这个Activity它的onCreate(),onStart()方法不会被调用,因为它并没有发生改变。
3.singleTask:栈内复用模式
这个模式比较复杂,当一个具有singleTask模式的Activity A请求启动后,系统会寻找A想要的任务栈,这个任务栈就是通过taskAffinity
属性指定,后面会做介绍。如果不存在,需要创建一个A想要的任务栈,然后在创建A的实例后把A放到栈中;如果已经存在A想要的任务栈,这时需要判断A是否在栈中有实例存在,如果存在,那么系统会把A掉到栈顶并调用onNewIntent
方法,与此同时singleTask默认有clearTop
效果,这样A上面的Activity会全部出栈;如果不存在A的实例,则创建A的实例并把A放入栈中。
4.singleInstance:单实例模式
该模式具备singleTask模式的所有特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具有全局唯一性,即整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的Activity实例,除非这个特殊的任务栈被销毁了。以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
TaskAffinity
顾名思义,任务相关性。这个参数设置了Activity所需要的任务栈的名字,默认情况下,所有Activity所需要的任务栈的名字都为应用的包名,可以通过taskAffinity为Activity设定任务栈的名字(除包名以为,不然相当于没有设定)。
<activity
android:name=".view.ThirdActivity"
android:taskAffinity=".ThirdActivity"
android:launchMode="singleTask">
</activity>
注意点:
taskAffinity属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,其他情况下没有意义。
taskAffinity属性值为字符串,而且中间必须要有包名分隔符“.”这个符号,否则无法安装,会报错
Installation failed with message INSTALL_FAILED_USER_RESTRICTED: Invalid apk.
allowTaskReparenting用来标记Activity能否从启动的Task移动到taskAffinity指定的Task,默认是继承至application中的allowTaskReparenting=false,如果为true,则表示可以更换;false表示不可以。
allowTaskReparenting = "true"
例如:
在一个E-Mail邮件内容中,包含一个web页的链接,点击它就会启动一个Activity来显示这个页面。但是这个Activity是由浏览器应用程序定义的,那么现在它作为e-mail Task(任务)的一部分。如果它重新宿主到Browser Task里,当Browser下一次进入到前台时,它就能被看见(上一次从邮件中打开的地址),并且,当e-mail Task再次进入前台时,就看不到它了。