一、 生命周期
Android使用Task管理活动,一个任务就是一组存放在栈里的活动集合,被叫做返回栈。
启动新活动时入栈,并处于栈顶位置,销毁活动时,栈顶元素出栈。
系统总是会显示处于栈顶的活动。
活动状态
1.运行状态:当活动位于栈顶时,处于运行状态
2.暂停状态:当活动不再处于栈顶位置,但仍然可见时,活动进入暂停状态
3.停止状态:当活动不再处于栈顶位置并且完全不可见时,活动进入停止状态。
4.销毁状态:活动从返回栈中移除。
正常情况下的生命周期
活动的生存期
Activity类中定义了7种回调方法
java
onCreate():每个活动都重写,在活动第一次被创建时调用。
onStart():在活动由不可见变为可见时调用,可见,但不在前台无法交互
onResume():在活动准备好和用户交互时调用,此时活动位于栈顶并处于运行状态,可见并在前台出现
onPause():在系统准备启用或恢复另一个活动时调用,释放资源并保留关键数据
onStop():在活动完全不可见时调用
onDestory():在活动销毁前调用,之后活动变为销毁状态
onRestart():在活动由停止状态变为运行状态时调用
完整生存期:在onCreate和onDestory之间经历,活动在onCreate初始化在onDestory释放内存。
可见生存期:在onStart和onStop之间经历,管理对用户可见资源,在onStart加载资源,在onStop释放资源
前台生存期:在onResume和onPause之间经历,在前台生存期内活动总处于运行状态,此时活动可以和用户交互。
**正常切换到桌面或打开新Activity**
onPause->onStop
**如果新Activity采用透明主题**
不回调onStop
**当打开新Activity**
先执行旧Activity的onPause再启动新Activity
异常情况下的生命周期
1.资源相关的系统配置发生改变导致Activity被杀死并重新创建
例如配置了横屏和竖屏两种资源文件,当旋转屏幕时,由于系统配置发生改变,在默认情况下,Activity会被销毁并重新创建
此时属于异常情况下终止,系统会调用onSaveInstanceState保存当前Activity的状态(在onStop之前);重新创建Activity后,系统会调用onRestoreInstanceState,将onSaveInstanceState方法保存的Bundle对象作为参数传递给onRestoreInstanceState(onStart之后调用)和onCreate
在异常情况下需要重建时,系统会为我们保留Activity的当前视图结构,再重启后恢复这些数据(如文本框中输入的内容,ListView的滚动位置等)。
每一个View都有onSaveInstanceState和onRestoreInstanceState,其中的具体实现就是系统自动为View保留的数据。
保存和恢复View的层级结构:Activity调用onSaveInstanceState->Activity委托Window保存数据->Window委托它上面的顶级容器(ViewGroup,一般是DecorView)保存数据->顶层容器一一通知子元素保存数据**(典型委托思想,上层委托下层,父容器委托子元素,应用:View的绘制,事件分发)**
onRestoreInstanceState和onCreate获取保存数据的区别:onRestoreInstanceState一旦被调用,其参数Bundle一定有值,不必判空;onCreate正常启用Bundle为null需要额外判断。
系统只会在Activity即将被销毁并有重新显示的机会时才会调用onSaveInstanceState
2.资源内存不足导致其优先级低的Activity被杀死
Activity的优先级(从高到低):前台Activity(正在和用户交互的Activity)->可见但非前台Activity(如对话框)->后台Activity(已被暂停)
当内存不足时,系统会杀死优先级低的Activity所在进程,后续通过onSaveInstanceState和onRestoreInstanceState来存储和恢复数据。
将后台工作放入Service中保证有一定的优先级,保证不会被系统回收。
3.不想重新创建Activity,指定configChanges属性
在AndroidMenifest.xml中加入Activity的声明
configChanges的常见项目及其含义
locale:设置的本地位置发生了改变,一般指切换了系统语言
orientation:屏幕方向发生改变,如旋转了屏幕
keyboardHidden:键盘的可访问性发生了改变,如用户调出键盘
screenSize:屏幕尺寸信息发生了改变,当编译选项中的minSdkVersion和targetSdkVersion均低于13时不会重启Activity
smallScreenSize:设备的物理屏幕尺寸发生改变,当编译选项中的minSdkVersion和targetSdkVersion均低于13时不会重启Activity
系统不重新创建,会调用onConfigurationChanged方法
二、 活动的启动模式
分别为standard,singleTop,singleTask和singleInstance,可以在AndroidManifext.xml中通过给标签指定android:launchMode属性选择启动模式
standard
默认启动模式,启动新活动时都会在返回栈中入栈并处于栈顶位置,系统不会在乎活动是否已经在栈中存在,每次启动都会创建该活动的新实例。
谁启用了这个Activity就会进入启用他的Activity的所在栈。使用非Activity类型的Context没有任务栈,此时会报错,需要为待启动Activity指定FLAG_ACTIVITY_NEW_TASK标记位,会为他重新创建一个任务栈。
singleTop
在启动活动时如果返回栈的栈顶已经是该活动,则不会创建新实例。当该活动不是栈顶时,依然会创建新实例。
<activity
android:name=".FirstActivity"
android:exported="true"
android:launchMode="singleTop"
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
此时会调用Activity的onNewIntent方法
singleTask
启动活动时系统首先检查栈中是否存在该活动的实例,发现存在直接使用该实例,并把在这个活动之上的活动都出栈,没有则创建新的活动实例。此时会调用Activity的onNewIntent方法。
<activity
android:name=".FirstActivity"
android:exported="true"
android:launchMode="singleTask"
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
singleInstance
会启用一个新的单独的返回栈来管理这个活动,不管哪个应用程序来访问这个活动,都有一个共同的返回栈
<activity
android:name=".FirstActivity"
android:exported="true"
android:launchMode="singleInstance"
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Activity所需任务栈
TaskAffinity: 任务相关性,标识了Activity所需任务栈的名字,默认情况下所有Activity的所需任务栈名字为应用的包名
可以为每个Activity单独指定TaskAffinity属性,为了和singleTask启动模式或allowTaskReparenting属性配对使用。
任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity位于暂停状态
allowTaskReparenting 是一个在 AndroidManifest.xml 的 <activity> 标签中设置的属性。它控制着一个 Activity 在不同 任务(Task) 之间的"转移"能力。
当应用A启用了应用B的某个Activity时,当allowTaskReparenting属性为true时,当应用B被启动,此Activity会从应用A的任务栈转到应用B的任务栈
简单来说:
当一个应用 A 启动了一个原本"属于"应用 B 的 Activity 时,这个被启动的 Activity 可以选择"认祖归宗",从应用 A 的任务栈转移到应用 B 的任务栈中,特别是当应用 B 被切换到前台时。
指定启动模式的两种方式:
1.通过AndroidMenifest的launchMode指定
2.通过在Intent中设置标志位指定
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
2的优先级大于1,第二种方法无法为Activity指定singleInstance模式
三、 活动的的标记位
标记位的作用:设定Activity的启动模式,影响Activity的运行状态。
标记位的常见参数如下
FLAG_ACTIVITY_NEW_TASK:为Activity指定singleTask启动模式
FLAG_ACTIVITY_SINGLE_TOP:为Activity指定singleTop启动模式
FLAG_ACTIVITY_CLEAR_TOP:Activity启动时,在同一个任务栈中所有位于他上面的Activity都要出栈;如果被启动的Activity采用standard模式启动,它和它之上的Activity都要出栈,系统会创建新的实例入栈
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:这个Activity不会出现在历史Activity列表中