活动的生命周期
返回栈
Android使用任务(Task)来管理活动。一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack)。启动新活动时,该活动入栈,居于栈顶。按下Back键或调用finish()
方法销毁活动时,处于栈顶的活动出栈,前一个入栈的活动居于栈顶。系统总是显示处于栈顶的活动给用户。
活动状态
每个活动在生命周期内最多有4种状态。
- 运行状态:活动位于返回栈栈顶时。系统最不愿意回收这种状态的活动。
- 暂停状态:活动不再处于栈顶但依然可见时(比如处在对话框活动之下的活动)。系统也不愿意回收此类活动。
- 停止状态:活动不在栈顶且完全不可见时。系统仍会为其保存相应的状态和成员变量,但当需要内存时有可能会被系统回收。
- 销毁状态:活动从返回栈移除后。系统最倾向于回收此类活动。
活动生存期
Activity
类中提供了7个回调方法,可将活动的生命周期分成3个生存期。
- 完整生存期:在创建新活动时调用的
onCreate()
方法和销毁活动时调用的onDestory()
方法之间的周期。 - 可见生存期:活动在由不可见变为可见时调用
onStart()
方法和在完全不可见时调用onStop()
方法之间的周期。 - 前台生存期:活动在处于运行状态,准备好与用户交互时调用
onResume()
方法与活动被挂起,系统准备去启动或恢复另一活动时调用onPause()
方法之间的周期。onPause()
方法中通常释放一些消耗CPU的资源,保存一些关键数据,但方法执行速度一定要快。 onRestart()
方法负责把活动从停止状态恢复为运行状态,即从onStop()
后的活动执行,之后会执行onStart()
方法。
在活动被回收前保存临时数据
Activity
类中提供了一个onSaveInstanceState()
回调方法,该方法可以保证在活动被回收之前一定会被调用。- 该方法会携带一个
Bundle
类型的参数。Bundle
提供了一系列方法用于保存数据,比如用putString()
方法保存字符串,用putInt()
方法保存整形数据,以此类推。 - 每个保存方法需要两个参数:键,相当于成员名,变量名,用于之后从
Bundle
中取值;第二个参数是要保存的值。 - 只需在
onCreate()
方法中传入之前保存的Bundle
就可以在方法中取出之前保存的值。 - 可以把
Bundle
存放在Intent
里实现跨活动传递数据。
活动的启动模式
- 主要是决定返回栈与返回栈中活动实例个数的设置,一共有四种,分别是standard,singleTop,singleTask,singleInstance,可以在
AndroidManifest.xml
中通过给<activity>
标签指定android:launchMode
属性选择启动模式。 - standard模式下,每当启动一个新的活动,系统就会创建一个新的实例,它会入栈且处于栈顶。换句话说,standard模式对活动在返回栈中的唯一性不做任何保证。
- 用
this.toString()
方法可以把当前活动实例转换成字符串。 - singleTop模式下,在启动活动时如果发现返回栈栈顶已经是该活动的一个实例则不再启动新活动。
- singleTask模式下,在启动活动时如果发现返回栈中存在该活动实例则将其上所有活动都出栈使其置顶。
- 实际上我们在使用时发现,对于设置了”singleTask”启动模式的Activity,它在启动的时候,会先检测系统中属性值affinity等于它的属性值
taskAffinity
的task是否存在;如果存在这样的task,它就会在这个task中启动,否则就开启一个新的task。而taskAffinity
默认情况下是应用的包名,即默认时并不会新建一个task。 - 因此,如果我们想要设置了”singleTask”启动模式的Activity在新的task中启动,就要为它设置一个独立的
taskAffinity
属性值。下面的代码中,应用程序的包名是com.fred.testactivity,我们将BActivity的启动模式设置成singleTask, 同时设置其taskAffinity属性为com.fred.testactivity.BActivity 。当BActivity启动时,会发现多了一个task 。代码如下:1
2
3
4
5
6<activity
android:name=".BActivity"
android:label="@string/title_activity_b"
android:launchMode="singleTask"
android:taskAffinity="com.fred.testactivity.BActivity">
</activity>
- 实际上我们在使用时发现,对于设置了”singleTask”启动模式的Activity,它在启动的时候,会先检测系统中属性值affinity等于它的属性值
==注== 此时该活动实例将会从停止/暂停状态恢复至运行状态,注意与活动生命周期结合理解。
- singleInstance模式下,在整个系统中都只存在一个实例,因为系统会为该活动实例创建一个单独的返回栈。
- 使用
getTaskId()
可以获取当前任务ID的字符串。
关于活动的技巧
知道当前界面对应的活动
- 用一个普通Java类作为
AppCompatAvtivity
的父类(e.g.BaseActivity
),再让所有活动都继承该类,在该类中重写onCreate()
方法,打印一条以getClass().getSimpleName()
作为内容的日志即可。getSimpleName()
为获取当前类的简写名。
随时随地退出程序
- 新建一个
Activity
列表类,在其中写添加、去除Activity项以及借助finish()
方法来结束列表中所有Activity的静态方法(e.g.finishAll()
,静态是为了无需创建列表的实例) - 在之前的
BaseActivity
中重写onCreate()
和onDestroy()
方法,加入在列表中添加、删除活动的方法调用。 - 接下来只需在需要结束所有活动的地方调用
finishAll()
方法即可。 - 也可以在
finishAll()
方法后加上杀掉当前进程的代码保证程序完全退出1
2
3android.os.Process.killProcess(android.os.Process.myPid());
//killProcess()方法只能杀掉自己
//通过myPid()方法获取当前进程的id
启动活动的更好方法
- 在活动中自己写一个
actionStart()
方法,在方法中通过传入的参数完成构建启动活动的Intent和调用startActivity()
。 - 这样的好处在于可以清楚地看到需要传递的数据有哪些,而且在需要启动活动时只需调用该方法,无需再自己创建Intent等。