1.2 Activity
和任务
如前所述,一个Activity
可以启动其他的,包括不同应用程序定义的Activity
。例如,假设想让用户看到某个地方的街道地图。而且已经有一个Activity
具有此功能,那么我们的Activity
只需要把必要的信息打包到Intent
对象并把它传递给startActivity()
。于是地图浏览器就会显示那个地图。而当用户按下BACK
键的时候,我们的Activity
又会再次显示在屏幕。
对于用户而言,这看起来就像是地图浏览器是我们的Activity
所在的应用程序中的组成部分,尽管它是由其他应用程序定义,并运行在那个应用程序的进程之中。Android
将这两个Activity
放在同一个任务中来维持一个完整的用户体验。简单的说,任务就是用户所体验到的“应用程序”。它是安排在一个堆栈中的一组相关的Activity
。堆栈中的根Activity
就是启动任务的Activity
——通常,它就是用户在应用程序加载器中所选择Activity
。而堆栈最上方的Activity
则是当前运行的——直接响应用户操作。当一个Activity
启动另外一个的时候,新的Activity
就被压入堆栈,并成为当前运行的Activity
。而前一个Activity
仍保持在堆栈之中。当用户按下BACK
键的时候,当前Activity
出栈,而前一个恢复为当前运行的Activity
。
堆栈中保存的其实是对象,所以如果堆栈有相同Activity
之类的多个实例(例如多个地图浏览器),堆栈会独立保存每个实例。堆栈中的Activity
永远不会重新排列,只有压栈和出栈。
任务其实就是Activity
的堆栈,而不是manifest
文件中的一个类或者元素。所以我们无法撇开Activity
而为一个任务设置一个值。而事实上整个任务使用的值是在根Activity
中设置的。例如,下一节我们会谈及“任务的Affinity
”,这个值就是根Activity
的Affinity
设置中读出。
任务中的所有Activity
是作为一个整体进行移动的。整个任务(整个Activity
堆栈)可以移到前台,或退至后台。例如,设想当前任务堆栈中存有四个Activity
——三个在当前Activity
之后。当用户按下HOME
键回到应用程序加载器,然后选择一个新的应用程序(事实上是一个新任务)。则当前任务进入后台,而新任务的根Activity
显示出来。然后,用户很快再次回到应用程序加载器而又选择了前一个应用程序(前一个任务)。于是前面的任务,包括堆栈中所有的四个Activity
,再次回到前台。当用户按下BACK
键的时候,屏幕不会显示出用户刚才离开的Activity
(上一个任务的根Activity
)。取而代之,当前任务堆栈中最上面的Activity
被弹出,而同一任务中的上一个Activity
被显示出来。
上述行为都是Activity
和任务的默认行为。但是有方法可以改变所有这一切。Activity
和任务的联系、任务中Activity
的行为方式,都是由启动Activity
的Intent
对象中设置的一系列标记和manifest
文件中对应Activity
中的<activity>
元素的系列属性相互协作进行控制。请求发出者和回应者在这里都拥有话语权。
我们刚才所说的关键Intent
标记如下:
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP
而主要的<activity>
属性是:
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
接下来的一节会描述这些标记以及属性的作用,它们是如何互相影响的,以及使用它们的时候必须考虑的因素。
1.2.1 Affinity
(亲缘性)和新任务
默认时,应用程序中的所有Activity
相互之间都有一种Affinity
——即,它们都属于相同的任务。但是,可以在<activity>
元素的taskAffinity
属性为每个Activity
设置独立的Affinity
。因此不同应用程序定义的Activity
可以共享系统的Affinity
、定义在相同应用程序中Activity
也可以有不同的Affinity
。Affinity
在两种情况下产生作用:当启动Activity
的Intent
对象包含了FLAG_ACTIVITY_NEW_TASK
标记,或者当Activity
的allowTaskReparenting
属性设置为“true
”时。
v
FLAG_ACTIVITY_NEW_TASK
标记
如前所述,默认时,新的Activity
会加入到调用startActivity()
方法的Activity
所在的任务之中。并压入了调用者所在的相同堆栈。但是,如果传递给startActivity()
的Intent
对象包含了FLAG_ACTIVITY_NEW_TASK
标记,系统会为新Activity
寻找一个不同的任务。通常,正如标记所暗示的那样,是一个新任务。但这并不是必然的。如果已经存在一个与新Activity
有相同Affinity
的任务,则新Activity
会加入那个任务之中。如果不存在,则开启新的任务。
v
allowTaskReparenting
属性
如果Activity
的allowTaskReparenting
属性设置为“true
”,当具有与相同Affinity
的任务转到前台时,该Activity
就可以从初始的任务转移到该任务之中。例如,设想一个旅行应用程序定义了一个预报所选城市天气的Activity
。它与这个应用程序中的其它Activity
具有相同的Affinity
(默认的Affinity
)而且允许重定父级。我们的一个Activity
启动了天气预报,因此它与我们的Activity
属性相同的任务。但是,当旅行应用程序再次回到前台的时候,这个天气预报Activity
会被再次调整到原先的任务之中并显示。
如果一个.apk
文件中包含了多个用户视觉看到的“应用程序”,我们可能需要为相关的Activity
赋予不同的Affinity
。
1.2.2
启动模式
元素<activity>
的launchMode
属性可以设置四种不同的加载模式:
“standard
”(默认值)
“singleTop”
“singleTask”
“singleInstance”
这些模式之间的差异主要体现在四个方面:
v
哪个任务会保留对Intent
做出响应的Activity
。
对于“standard
”和“singleTop
”模式,是生成Intent
(并调用 startActivity()
)的任务——除非Intent
对象包含FLAG_ACTIVITY_NEW_TASK
标记。如果设定了该值,正如前一节Affinitie
和新任务所述,会选择不同的任务。
相反,对于“singleTask
”和“singleInstance
”模式,Activity
总是位于任务的根部。正是它们定义了一个任务,所以它们绝不会被加载到其它任务之中。
v
Activity
是否可以存在多个实例。
“standard
”或者“singleTop
”Activity
可以被多次实例化。它们可以属于多个任务,而一个任务也可以拥有相同Activity
的多个实例。
相反,对于“singleTask
”和“singleInstance
”的Activity
被限定只能有一个实例。因为这些Activity
都是任务的起源,这种限制意味着在一个设备中同一时间只允许存在一个任务实例。
v
实例所在的任务中是否有其他的Activity
。
“singleInstance
”模式的Activity
将以唯一的Activity
出现在它所在的任务。如果启动了别的Activity
,不管是何种启动模式,新的Activity
都将加载到其它的任务之中——如同在Intent
中设置了FLAG_ACTIVITY_NEW_TASK
标记一样的效果。在其它所有方面,“singleInstance
”模式的效果与“singleTask
”相同。剩下的三种模式允许一个任务中出现多个Activity
。“singleTask
”模式的Activity
将是任务的根Activity
,但它可以启动别的Activity
并将它们加入到所在的任务之中。“standard
”和“singleTop
”模式的Activity
可以在堆栈的任意位置出现。
v
是否要加载新的类实例来处理新的Intent
。
对于默认的”standard
“模式,每次都会创建一个新的实例来响应新的Intent
,每个实例仅处理一个Intent
。对于“singleTop
”模式,如果Activity
位于目标任务堆栈的最上面,则重用该Activity
来处理新的Intent
。如果它不是位于堆栈顶部,则不会使用它。而是创建一个新的实例来处理新的Intent
并将其加入堆栈。
例如,设想一个任务的堆栈由根Activity A
和Activity B
、C
和位于堆栈顶部的D
组成,即堆栈A-B-C-D
。一个针对D
类型Activity
的Intent
到达的时候,如果D
是默认的“standard
”启动模式,则创建并加载一个新的类实例,于是堆栈变为A-B-C-D-D
。但是,如果D
的启动模式为“singleTop
”,则现有的实例D
则会处理新的Intent
(因为它位于堆栈顶部)而堆栈保持A-B-C-D
的结构。
另一方面,如果新到达的Intent
是针对B
类型的Activity
,则无论B
的模式是“standard
”还是“singleTop
”,都会加载一个新的B
实例(因为B
不位于堆栈的顶部),而堆栈的顺序变为A-B-C-D-B
。
如前所述,“singleTask
”或“singleInstance
”模式的Activity
永远不会存在多个实例。所以该实例将处理所有的新Intent
。“singleInstance
”模式的Activity
永远保持在堆栈的顶部(因为它是堆栈中唯一的Activity
),因此它一直位于该处理Intent
的位置。但是,对于“singleTask
”模式的Activity
,它的任务堆栈上面可能有,也可能没有其他的Activity
。如果有,它就不在能够处理Intent
的位置上,则那个Intent
被抛弃。(即便在Intent
被抛弃的情况下,它的到底仍将使这个任务切换至前台并一直保留。)
当现有的Activity
被要求处理新的Intent
时,会调用他的onNewIntent()
方法并将Intent
对象传入。(原始启动Activity
的Intent
对象可以通过调用getIntent()
方法获得。)
请注意,当创建一个新的Activity
实例来处理新的Intent
时,用户总是可以按下BACK
键来回到前面的状态(回到前一个 Activity
)。但是当使用现有的Activity
来处理新Intent
的时候,用户是不能靠按下BACK
键回到当这个新Intent
抵达之前的状态的。
关于启动模式的更多信息,请参阅AndroidManifest.xml
文件。
1.2.3
清理堆栈
如果用户离开一个任务很长一段时间,系统会清理该任务中除了根Activity
之外的所有Activity
。当用户再次回到这个任务的时候,除了只剩下初始Activity
尚存之外,其余都跟用户离开任务的时候一样。这样设计的原因在于:过一段时间之后,用户再次回到一个任务的时候,很可能希望放弃之前所做的工作,开始新的事情。
这些属于默认行为,当然也有一些Activity
属性来控制并改变这些行为:
v
alwaysRetainTaskState
属性
如果任务的根Activity
的此属性设置为“true
”,则上述默认行为不会发生。任务将在很长的一段时间内保留堆栈内的所有Activity
。
v
clearTaskOnLaunch
属性
如果任务的根Activity
的此属性设置为“true
”,则每当用户离开这个任务和返回它的时候,堆栈都会被清空只留下根Activity
。换句话说,这是alwaysRetainTaskState
的另一个极端。即使是短暂的离开,用户回到任务时,也是它的初始状态。
v
finishOnTaskLaunch
属性
这个属性与clearTaskOnLaunch
属性相似,但它仅作用于单个的Activity
,而不是整个的任务。而且它可以使任意Activity
都被清理,包括根Activity
。当它设置为“true
”的时候,此Activity
仅做为任务的一部分存在于当前回话中,一旦用户离开并再次回到这个任务,此Activity
将不再存在。
还有另外一种方法将Activity
从堆栈中强制移除。如果Intent
对象包含FLAG_ACTIVITY_CLEAR_TOP
标记,而且目标任务的堆栈中已经存在了一个能够响应此Intent
的Activity
类型的实例,则这个实例之上的所有Activity
都将被清理以使它位于堆栈的顶部来响应Intent
。如果指定的Activity
的启动模式为“standard
”,则它本身也会从堆栈中移除,并启动一个新的实例来处理新的Intent
。这是因为加载模式为“standard
”的Activity
总会创建一个新实例来处理新的Intent
。
FLAG_ACTIVITY_CLEAR_TOP
与FLAG_ACTIVITY_NEW_TASK
经常合并使用。这时,这些标记提供了一种方法:定位其它任务中现存的Activity
、并将它们置于可以对Intent
做出响应的位置。
1.2.4
启动任务
当Activity
的Intent Filter
的动作指定为“android.intent.action.MAIN
”,类型指定为“android.intent.category.LAUNCHER
”(前面对Intent Filter
一节中已经有一个此类型的示例),它就被设定为任务的入口点。这样的过滤器设置会在应用程序加载器中为此Activity
显示一个图标和标签,以供用户加载任务或者在加载之后在任意时间返回到这个任务。
第二个功能相当重要:用户必须可以离开一个任务,并在一段时间后返回它。出于这个考虑,总是会初始化一个新任务的启动模式“singleTask
”和“singleInstance
”,这两种模式仅能用于指定了MAIN
和LAUNCHER
过滤器的Activity
。例如,如果没指定这样的过滤器将会发生什么呢:用Intent
启动了一个“singleTask
”的Activity
,初始化了一个新任务,用户在这个任务中花费了一些时间来完成工作。然后用户按下HOME
键。该任务切换至后台并被主屏幕所覆盖。由于它并没有在应用程序加载器中显示图标,这将导致用户再也无法回到它。
FLAG_ACTIVITY_NEW_TASK
标记也可能引起类似的问题。如果此标记使一个Activity
启动了一个新任务继而用户按下了HOME
键离开了它,则用户必须要有一些方法再次回到这个任务。一些实体(比如通知管理器)总是在外部任务中启动新的Activity
,而不是做为它们自己的一部分,所以它们总是将FLAG_ACTIVITY_NEW_TASK
标记包含在Intent
里面并传递给startActivity()
。如果写了一个能被外部实体使用这个标记调用的Activity
,我们必须注意要给用户留一个返回这个被外部实体启动的任务的方法。
当不希望让用户再次返回一个Activity
时,可以将<activity>
元素的finishOnTaskLaunch
设置为“true
”。参考前面的清理堆栈。
分享到:
相关推荐
《Android SDK 1.5 开发指南中文版》是一份针对Android 1.5版本的开发者文档,旨在帮助开发者理解并掌握在该版本下进行应用开发的基本概念和技术要点。这份文档详细介绍了Android应用程序的框架、关键类、组件、...
Android应用程序框架开发指南中文版 chm,本小册子是对Android SDK1.5版的英文开发资料Android Development Guide一文应用程序框架部分的翻译,覆盖了Android应用开发所有主要的概念。部分内容整理自网络。本文仅...
《Android开发指南中文版》是针对Android SDK 1.5版本的应用程序框架部分进行的翻译,旨在为开发者提供全面的Android应用开发基础知识。本指南涵盖了从核心概念到具体实现的各个层面,帮助开发者理解Android应用架构...
《Android开发指南中文版》是针对Android SDK 1.5版本的开发文档的中文翻译,旨在为开发者提供全面的Android应用开发基础知识。本指南涵盖了从应用程序的基础到组件的使用,再到进程和线程管理等多个重要方面,对于...
《Android开发指南中文版》是针对Android SDK 1.5版本的英文开发文档《Android Development Guide》的应用程序框架部分的翻译,旨在帮助开发者全面理解Android应用开发的核心概念。以下是该指南涉及的一些关键知识点...
《Android开发指南中文版》是针对Android SDK 1.5版本的应用程序框架部分的翻译,旨在为开发者提供全面的Android应用开发基础知识。本指南涵盖了从应用程序基础到组件管理、进程和线程等核心概念。 **应用程序基础 ...
3. **Android SDK**:需要下载并安装 Android SDK 2.1 版本。 4. **Eclipse IDE**:推荐使用 Eclipse 3.4 及以上版本,且需安装 Android Development Tools (ADT) 插件。 #### 三、详细步骤 ##### 1. 安装 JDK ...
通过以上章节的详细解析,我们可以看到《Beginning Android Application Development》这本书不仅涵盖了Android开发的基础知识,还深入探讨了许多高级主题和技术细节,为初学者提供了一个全面的学习框架。...
《Android API中文版》是为开发者提供的一份详尽的Android SDK参考资料,它包含了从基础概念到高级特性的全面解析,旨在帮助开发者更好地理解和运用Android平台。这份文档不仅提供了PDF版,适合打印阅读,还特别制作...
### Android开发指南中文版知识点概览 #### 一、Android 应用程序框架概述 本文档是基于Android SDK 1.5版本的英文开发资料《Android Development Guide》的应用程序框架部分翻译而成,主要针对Android应用开发的...
【Android 官方开发教程中文版】是一份详细的文档,主要针对初学者,旨在教授如何创建首个Android应用程序。这份教程涵盖了Android开发的基础知识,包括环境配置、项目创建、用户界面设计以及基本的用户输入处理。 ...