Activity是一个应用组件, 单个的Activity代表一个单独的屏幕界面,用户可与其提供的屏幕进行交互。
一、任务和返回栈
一个应用通常包含多个Activity,Android系统使用任务(Task)来管理这些Activity,一个任务就是一组存放在栈里的Activity的集合,这个栈也叫做返回栈,Activity 按照各自的打开顺序排列在栈(即返回栈)中。
任务(Task)是可以跨应用的,这正是任务存在的一个重要原因。有的Activity,虽然不在同一个应用中,但为了保持用户操作的连贯性,把他们放在同一个任务中。例如,在我们的应用中的一个Activity A中点击发送邮件,会启动邮件程序的一个Activity B来发送邮件,这两个activity是存在于不同应用中的,但是被系统放在一个任务中,这样当发送完邮件后,用户按back键返回,可以返回到原来的Activity A中,这样就确保了用户体验。
我们知道,栈是一种“后进先出”的数据结构,默认情况下,每创建一个新的Activity,它会在返回栈中入栈,并处于栈顶位置。当我们按下返回按钮或者调用finish()销毁栈顶活动时,位于栈顶的活动出栈,前一个栈即成为新的栈顶。系统总是会显示处于栈顶的Activity给用户。
二、Activity 生命周期
(1)Activity的四种状态
Activity在其生命周期中最多有四种状态:
- 运行状态
当一个Activity位于返回栈的栈顶时,该Activity就处于运行状态。 - 暂停状态
当一个Activity不处于栈顶位置但仍可见时,该Activity就处于暂停状态。例如,若一个Activity被一个弹出的未占满屏幕的对话框Activity遮住了,但是未完全遮住,则此时该Activity就处于暂停状态 - 停止状态
当一个Activity不再处于栈顶位置且完全不可见时,该Activity就处于停止状态 - 销毁状态
当一个Activity从返回栈中移除后就进入了销毁状态。
以上四种状态的Activity,为了保证手机内存充足,系统最倾向于回收销毁状态的Activity,其次是处于停止状态的Activity,对于可见状态(暂停状态和运行状态)的Activity,只有在内存极低的情况下系统才会考虑回收,且系统最不愿意回收处于运行状态的Activity,因为此时的Activity正与用户直接交互,若强行回收会带来极差的用户体验。
(2)Activity的七种回调方法
如上图所示,Activity类定义了七个回调方法来表示Activity生命周期的不同环节:
- onCreate()
在Activity第一次被创建的时候调用。 - onStart()
当Activity由不可见变为可见状态时调用。 - onResume()
当Activity准备好与用户进行交互时调用。此时活动一定处于运行状态,且位于返回栈栈顶。 - onPause()
在系统准备去启动或者恢复另一个Activity时调用。该方法一般用于保存一些关键数据以及释放掉一些消耗CPU的资源。 - onStop()
在Activity完全不可见时调用。 - onDestory()
在Activity被销毁之前调用。之后Activity即变为销毁状态。 - onRestart()
在Activity由停止状态变为运行状态之前调用,也即Activity被重新启动了
(3)Activity的三种生存期
以上七个方法中,出了onRestart()方法,其他方法都是两两对应的,我们可以将Activity分为三种生存期:
(1)完整生存期:onCreate()<-->onDestory()
(2)可见生存期:onStart()<-->onStop()
(3)前台生存期:onResume()<-->onPause()
(4)Activity的几种典型生命周期变化
我总结了几种典型情况下Activity的生命周期的变化:
- Activity第一次被创建时依次执行:
onCreate()-->onStart()-->onResume() - Activity被另一个Activity遮挡时(完全遮挡)依次执行:
onPause()-->onStop() - 然后按下back键返回上一个Activity:
onRestart()-->onStart()-->onResume() - 打开另一个对话框形式的Activity(部分遮挡):
onPause()-->按下back键返回-->onResume() - 按下back键退出程序:
onPause()-->onStop()-->onDestroy()
(5)Activity被回收的处理
在 Activity 生命周期中,Android 会在销毁 Activity 之前调用onSaveInstanceState(),以便保存有关应用状态的数据。
@Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putString("message", text.getText().toString());
}
我们可以在onCreate()中取出Activity销毁之前保存的数据来恢复 Activity 状态。
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState != null)
{
String message = savedInstanceState.getString("message");
}
}
除了在onCreate()中恢复外,我们还可以使用onRestoreInstanceState()函数来恢复数据,如下所示:
@Override
public void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
String message = savedInstanceState.getString("message");
}
需要注意的是,onSaveInstanceState()和onRestoreInstanceState()并不同于Activity的生命周期方法,它们并不一定会被触发。
例如,当应用遇到意外情况(如:内存不足、用户直接按Home键)由系统销毁一个Activity时,onSaveInstanceState() 会被调用。但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。
而onRestoreInstanceState()被调用的前提是,Activity确实被系统销毁了,而不是有可能被销毁。例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到Activity A,这种情况下Activity A一般不会因为内存的原因被系统销毁,故Activity A的onRestoreInstanceState()方法不会被执行。
通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。
三、Activity的启动模式
Activity有四种启动模式,分别为standard,singleTop,singleTask,singleInstance。如果要使用这四种启动模式,必须在manifest文件中<activity>标签中的launchMode属性中配置,如下所示,若不配置的话,默认为standard模式:
<activity android:name=".MainActivity"
android:label="@string/title_name"
android:theme="@android:style/Theme.Holo.Light"
android:launchMode="singleTask"
</activity>
- standard 标准模式,每次都新建一个实例对象
- singleTop 如果在任务栈顶发现了相同的实例(注意是栈顶),则调用原来栈顶实例的onNewIntent()方法来重用该实例,而不是新建一个实例。否则新建并压入栈顶
- singleTask 如果在任务栈中发现了相同的实例,将其上面的任务终止并移除,重用该实例。否则新建实例并入栈
- singleInstance 允许不同应用,进程线程等共用一个实例,无论从何应用调用该实例都重用
为了便于理解,特意画了几张示意图说明:
(1)standard:每次激活Activity时(startActivity),都创建Activity实例,并放入任务栈。
从图中可以看出,虽然当前栈顶为Activty2,但若再开启一个Activity2仍然会新建一个实例压入栈中成为新的栈顶。这种模式其实并不合理,每次都新建一个实例实在是浪费。事实上,我们可以根据实际情况采用下面的三种方式来进行优化。
(2)singleTop:如果某个Activity自己激活自己,即任务栈栈顶就是该Activity,则不需要创建,其余情况都要创建Activity实例。
采用这种模式可以很好地解决重复栈顶的问题,但是若活动并不处于栈顶,还是会重复创建多个实例。有没有办法可以让整个应用程序的上下文只存在某个Activity的一个实例呢?这就要用到singleTask模式了。
(3)singleTask:如果要激活的那个Activity在任务栈中存在该实例,则不需要创建,只需要把此Activity放入栈顶,并把该Activity以上的Activity实例都从栈中移除。
从上图中可以看到,当前栈顶为Activity3,开启Activity1,此时栈中存在Activity1,则将Activity1上面的Activity3、Activity2移除,使Activity1成为新的栈顶。
singleTop和singleTask看起来已经可以解决大部分重复创建实例的问题了。但是,若某个应用的某个Activity频繁被其他应用调用,那么情况又会怎样呢?我们知道,每个应用都会有自己的返回栈,同一个Activity被不同应用调用,必然会在不同应用的返回栈中都创建新的实例,而使用singleInstance就可以解决这个问题了。
(4)singleInstance:如果应用1的任务栈中创建了MainActivity实例,如果应用2也要激活MainActivity,则不需要创建,两应用共享该Activity实例;
从上图中可以看到,Activity3存放在一个单独的返回栈里,在singleInstance中,会有一个单独的返回栈来管理某个被其他应用频繁调用的Activity,不管哪个应用来访问这个Activity,都共用同一个返回栈,这也就解决了应用间共享Activity实例的问题。