一个Android应用通常包括多个Activity,这些Activity通力合作,提供一个完整的用户体验。一个Activity可以启动别的Activity,甚至可以启动别的应用程序的Activity。这看起来就好像别的应用程序的Activity是你的应用的一部分。即使这两个Activity来自不同的应用程序,Android系统仍然会将Activity保存在相同的任务中。以维护一个无缝的用户体验。
任务是指在在进行特定的作业时与用户交互的一系列Activity。这些Activity会按照打开的先后顺序排列在一个堆栈中,即返回栈。该返回栈按照后进先出的顺序管理堆栈中的所有Activity。设备的主屏幕是大多数任务的起点。当用户触摸应用的启动图标时,该应用的任务将出现在前台。如果该应用程序最近没有使用过或者用户从最近使用列表中删除。应用会创建一个新的任务,并且该应用的主Activity会作为任务的跟Activity打开。
例如一个Activity A启动另外一个Activity B时,Activity B会被压入堆栈中并处于堆栈顶部,Activity A仍然保留在堆栈中,但是处于停止状态。当用户按返回键时,栈顶的Activity B会从堆栈中弹出并销毁,而前一个Activity A会恢复执行。处于堆栈中的Activity实例永远不会被重新排序,只能被压入堆栈或从栈顶弹出。
首先从主屏幕点击启动图标,此时创建一个新的任务,该应用的主Activity A作为任务的跟Activity打开。此时Activity A处于返回栈的栈顶。在Activity A中启动了一个Activity B,Activity B被压入返回栈并处于栈顶,Activity A仍然保留在返回栈中,处于停止状态。在Activity B中又启动了一个Activity C,Activity C被压入返回栈并处于栈顶,Activity A和B仍然保留在返回栈中处于停止状态。此时,当用户按返回键按钮时,Activity C被弹出返回栈并销毁。处于Activity C下面的Activity B重回栈顶并恢复执行。继续按返回键,Activity B被弹出堆栈并销毁,处于Activity B下面的Activity A重回栈顶并恢复执行。如果用户继续按返回键,此时将返回到主屏幕,堆栈中的所有Activity均被移除,任务也不复存在。
任务是一个整体。当用户开始另一个新的任务或者按主页按钮返回到主屏幕时,当前任务会进入到后台。任务中的所有Activity都会被处于停止状态。当处于后台的任务返回前台时,用户能够回到离开时的状态。当处于后台的任务重新返回到前台时(例如从主屏幕触摸该任务的应用的启动图标),堆栈中的Activity保持不变,处于栈顶的Activity会恢复执行。
由于返回栈中的Activity实例不会重新排序,当有多个Activity启动一个相同的Activity时,会创建该Activity的实例并压入返回栈(而不是将该Activity的先前的任一实例置于返回栈的顶部)。这样,应用中的一个Activity可能会被多次实例化。如果不希望Activity多此实例化,可以更改Activity的启动模式。
Android Activity的启动模式
Activity的启动模式分为四种, 我们可以在清单文件中使用<activity>的launchMode属性为其指定。
一 standard ,该启动模式为默认模式,系统会在启动该Activity的任务中创建该Activity的实例并向其传送Intent,该Activity可以被多次实例化。而每个实例均可属于不同的任务,且一个任务可以拥有多个该Activity的实例。
例如,现在任务的返回栈中包含有根Activity的实例A-B-C-D ,且D实例处于栈顶,假如此时又收到针对D类Activity的Intent,则会又创建一个D的实例,此时返回栈中的Activity实例为A-B-C-D-D。
二 singleTop ,如果该任务的顶部存在一个Activity A的实例。系统在启动Activity A时并不会重新实例化Activity,会重用位于栈顶的Activity A的实例并调用其onNewIntent()方法向其传递Intent。该Activity可以被多次实例化且每个实例均可属于不同的任务,并且一个任务可以拥有多个实例(前提是启动Activity时该Activity的实例不处于栈顶)。
例如,现在任务的返回栈中包含有根Activity的实例A-B-C-D ,且D实例处于栈顶,启动模式为singleTop。假如此时又收到针对D类Activity的Intent,系统会重用处于栈顶D的实例,并通过onNewIntent()方法传递Intent,此时返回栈中Activity的实例依然为A-B-C-D。但是如果收到的是针对Activity B的Intent,则会向堆栈添加B的新实例,即使B的启动模式为singleTop。
三 singleTask ,系统会创建一个新的任务,但在创建新任务之前会检查要启动的Activity的任务栈是否存在,如果存在就不会创建新的任务而是直接使用。在创建该Activity的实例时,如果没有指定taskAffinity属性,系统会使用默认的任务栈名,即为应用的包名。但是如果该Activity的实例已经存在于一个任务中,则系统会重用该实例并调用onNewIntent()方法传递Intent,而不会创建新的实例。在重用该实例时,会将该实例前面所有的Activity移除出栈。一次只能存在一个Activity的实例。
例如,现有任务A的返回栈中包含有根Activity的实例A-B,B处于栈顶,此时收到一个针对C类的Activity的Intent,启动模式为singleTask且没有指定taskAffinity属性。由于任务栈的名称使用默认的应用包名和启动它的Activity相同,此时不会创建新的task而是直接使用。会创建Activity C的实例并压入的返回栈中。此时C处于栈顶。返回栈内中的Activity实例为A-B-C。这时又收到一个针对D类的Activity的Intent,启动的模式为默认,且未设置taskAffinity属性。会生成一个Activity D的实例并压入返回栈中。此时D处于返回栈的栈顶。返回栈内的Activity实例为A-B-C-D。假如此时又收到一个针对C类的Activity的Intent。则系统会重用返回栈内的Activity C的实例,并调用onNewIntent()方法传递Intent。在重用时会将C实例上的ActivityD移除出栈。此时返回栈中Activity的实例为A-B-C。
四 singleInstance ,系统会创建一个新的任务,只是不会将其他Activity的实例启动到包含该Activity实例的任务中,该Activity始终是其任务唯一仅有的成员,由该Activity启动的任何Activity都会在单独的任务中打开。
例如,现在任务A的返回栈中包含有根Activity的实例A-B,B处于栈顶,此时收到一个针对C类Activity的Intent,且启动模式为singleInstance。此时会启动一个新的任务B。并创建Activity C的实例压入任务B的返回栈中,该任务中仅有一个Activity C的实例。此时任务A会处于后台,其返回栈中的Activity实例A-B均处于停止状态,如果这时又收到一个针对D类Activity的Intent,启动模式为默认模式,且未设置taskAffinity属性。此时启动的Activity D会位于任务A中,且位于任务A返回栈的栈顶。这时任务A处于前台,任务B处于后台。这时如果按返回键,会将Activity D弹出任务A返回栈并销毁,其下面的Activity B会处于栈顶并恢复执行。继续按返回键,Activity B弹出返回栈,Activity A处于栈顶并恢复执行。继续按,这时Activity A弹出返回栈。任务A中的所有Activity都已经出栈,任务A不复存在。任务B返回前台,任务B中的Activity C恢复执行。继续按,Activity C出栈。任务B不复存在。返回到主屏幕。
关联taskAffinity
关联指的是Activity优先属于哪个任务。默认的情况下,同一个应用的的所有Activity彼此关联,同一个应用中的Activity位于同一个任务中。不过,我们可以改变这一默认行为。不同应用中定义的Activity可以共享关联,或者在一个应用中可以为不同的Activity分配不同的任务关联。
我们可以使用activity中的taskAffinity属性来修改任何给定Activity的关联。taskAffinity的值取字符串值,且必须与应用的包名不同。
taskAffinity属性会在这几种情况下起作用,当的Activity的启动模式为singleTask或singleInstance。或启动Activity的启动模式为singleTask或singleInstance。或者启动的Intent包含FLAG_ACTIVITY_TASK标志。又或者activity的allowTaskReparenting属性为true。设置该属性时,Activity可以从启动的任务移动到相关联的任务中。
清理返回栈
如果用户长时间离开任务,则系统会清除所有Activity的任务,只会保留根Activity。当用户返回到任务时。仅仅会恢复根Activity。如果想改变这种此种行为,可以通过以下几个activity的属性:
1 alwaysRetainTaskState 如果将根Activity的此属性设置为true,则会在用户离开很久以后也不会清除任务中的Activity。任务仍会将所有Activity保留在堆栈中。
2 clearTaskOnLaunch 如果将根Activity的此属性设置为true, 则每当用户离开任务后,系统会清除除根Activity的所有Activity实例。即使只离开任务片刻时间。
3 finishOnTaskLaunch 该属性仅对单个Activity起效,而非整个任务。如果将该属性设置为true时,该Activity仍是用户的一部分,但是仅限当前对话,如果用户离开任务后返回。则该Activity将在任务中不复存在。