`

Android开发之活动与任务

阅读更多

坚持就是胜利!关键是你能坚持吗?不能的话,你注定是个失败者。

引言

关于Android应用程序原理及术语,前面两篇:

介绍了Android应用程序的进程运行方式:每一个应用程序运行在它自己的Linux进程中。当应用程序中的任何代码需要执行时,Android将启动进程;当它不在需要且系统资源被其他应用程序请求时,Android将关闭进程。而且我们还知道了Android应用程序不像别的应用程序那样(有Main函数入口点),它没有单一的程序入口点,但是它必须要有四个组件中的一个或几个:活动(Activities) 、服务(Services) 、广播接收者(Broadcast receivers) 、内容提供者(Content providers)。且分别介绍它们的作用,及如何激活和关闭它们、如何在清单文件(AndroidManifest.xml)中声明它们及Intent过滤器。

在简单回顾之后,本篇还是继续介绍Android应用程序原理及术语——活动与任务(Activities and Tasks)。

  • 1、活动与任务概述
  • 2、亲和度和新任务(Affinities and new tasks)
  • 3、启动模式(Launch modes)
  • 4、清除栈(Clearing the stack)
  • 5、启动任务(Starting tasks)

1、活动与任务概述

如前所述,一个活动(activity)能启动另一个活动,包括定义在别的应用程序中的活动。再次举例说明,假设你想让用户显示某地的街道地图。而且已经有了一个活动能做这个事情(假设这个活动叫做地图查看器),因此你的活动要做的就是将请求信息放进一个Intent对象,然后将它传给startActivity()。地图查看器就启动并显示出地图。当用户点击返回按钮之后,你的活动就会重新出现在屏幕上。

对用户来说,这个地图查看器就好像是你的应用程序的活动一样,虽然它定义在其他的应用程序中且运行在那个应用程序的进程中。Android将这些活动保持在同一个任务task)中以维持用户的体验。简单地讲,任务是用户体验上的一个“应用程序”,是排成堆栈的一组相关活动。栈底的活动(根活动)是起始活动——一般来讲,它是用户在应用程序启动器(也称应用程序列表,下同)中选择的一个活动。栈顶的活动是正在运行的活动——它关注用户的行为(操作)。当一个活动启动另一个,新的活动被压入栈顶,变为正在运行的活动。前面那个活动保存在栈中。当用户点击返回按钮时,当前活动从栈顶中弹出,且前面那个活动恢复成为正在运行的活动。(关于栈的先进后出特性不要我在这里讲吧!)

栈中包含对象,因此如果一个活动(再次说明:活动是Activity的子类)启动了多个实例——例如多个地图查看器,则栈对每个实例有一个独立的入口。(可以这样理解:假设有四个活动以这样的顺序排在栈中——A-B-C-D,现在又有一个C的实例,则栈变成A-B-C-D-C,这两个C的实例是独立的。)栈中的活动从不会被重新排列,只会被压入、弹出。这点很好理解,因为活动的调用顺序是固定的。

任务是一栈的活动,而不是清单文件中声明的某个类或元素,因此无法独立于它的活动为任务赋值。整个任务的值是在栈底活动(根活动)设置的。例如,下节将讨论的“任务亲和度”,亲和度信息就是从任务的根活动中获取的。

一个任务的所有活动作为一个整体运行。整个任务(整个活动栈)可置于前台或发送到后台。例如,假设当前任务有四个活动在栈中——三个活动在当前活动下面。用户按下HOME键,切换到程序启动器,并选择一个新的应用程序(实际上是一个新的任务)。当前任务进入后台,新任务的根活动将显示。接着,过了一会,用户回到主屏幕并再次选择之前的应用程序(之前的任务)。那个任务栈中的所有四个活动都变为前台运行。当用户按下返回键时,不是离开当前任务回到之前任务的根活动。相反,栈顶的活动被移除且栈中的下一个活动将显示。

上面所描述的是活动和任务的默认行为,但是有方法来改变所有这些行为。活动与任务之间的联系及任务中活动的行为,是由启动活动的Intent对象的标志(flags)和清单文件中活动<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

接下来的小节将讨论这些标志和属性的作用,他们怎么交互,及使用的注意事项。

2、亲和度和新任务(Affinities and new tasks)

默认情况下,一个应用程序的所有活动互相之间都有一个亲和度(affinity——也就是说,他们属于同一个任务的偏好(preference)。然而,也可以通过<activity>元素的taskAffinity属性为每个活动设置个体亲和度。定义在不同应用程序中的活动能够共享亲和度,同一个应用程序中的活动可以分配不一样的亲和度。亲和度发挥作用的两种情况:1)启动活动的Intent对象包含FLAG_ACTIVITY_NEW_TASK标志时;2)一个活动的allowTaskReparenting属性为"true"时。

  • FLAG_ACTIVITY_NEW_TASK标志

如前所述,默认情况下,一个新的活动被启动到调用startActivity()方法的活动所在的任务。它被压入调用它的活动的栈中。但是,如果传递给方法的Intent对象包含FLAG_ACTIVITY_NEW_TASK标志,系统找一个不同的任务容纳活动。通常,顾名思义它表示一个新任务。但是,他并非一定如此。如果已经存在一个任务与新活动亲和度一样,该活动将启动到该任务。如果不是,则启动一个新任务。

  • allowTaskReparenting属性

如果一个活动的allowTaskReparenting属性为"true",它可以从启动它的任务转移到与它有亲和度并转到前台运行的任务中。例如,假设一个天气预报的活动,但选择城市是一个旅游应用程序的一部分。它与同一个应用程序中的其他活动具有相同的亲和度,且允许重新选择父活动(reparenting)。你的一个活动启动天气预报活动,因此他初始是跟你的活动属于同一个任务。但是,当旅游应用程序切换到前台运行时,天气预报活动将被重新分配和显示到该任务。

如果一个.apk文件,从用户的角度看包含不止一个“应用程序”,你可能要为与他们有关的些活动指定不一样的亲和度。

3、启动模式(Launch modes)

有四种不同的启动模式可以分配到<activity>元素的launchMody属性:

  • "standard"(默认模式)
  • "singleTop "
  • "singleTask"
  • "singleInstance"

这些模式的在以下四方面不同:

  • 哪个任务将持有响应意图(intent)的活动。对"standard"和"singleTop "模式,是产生意图的任务(调用startActivity()方法)——除非Intent对象包含FLAG_ACTIVITY_NEW_TASK标志。在那种情况下,像上一节亲和度和新任务(Affinities and new tasks)所描述的那样选择一个不同的任务。
    相反,"singleTask"和"singleInstance"模式,总是将活动标记为一个任务的根活动。他们定义一个任务,而从不启动到其他任务。
  • 活动是否可以实例化多次。"standard"或"singleTop "活动可以实例化多次。这些实例可以属于多个任务,且一个给定任务可以包含同一个活动的多个实例。
    相反,"singleTask"和"singleInstance"活动仅可以被实例化一次。因为这些活动是一个任务的根,这个限制意味着设备上一个时间只有不多于一个任务的实例。
  • 是否允许实例所在任务有其他活动。"singleInstance"活动所在任务只有它一个活动。如果他启动别的活动,那些活动将启动到不同的任务中,无论它的模式如何——就好像Intent对象包含FLAG_ACTIVITY_NEW_TASK标志。在所有其他方面,"singleInstance"模式等同于"singleTask"模式。
    其它三种模式允许多个活动属于一个任务。"singleTask"活动总是任务的根活动,但是它能启动其他活动到它的任务。"standard"或"singleTop "活动的实例可以出现的栈中的任何位置。
  • 响应一个意图时是否需要生成类的新实例。对于默认的"standard"模式,创建新的实例去响应每一个新的意图。每个实例仅处理一个意图。对于"singleTop "模式,一个类已存在的实例可以重新用了处理新的意图,如果它位于目标任务的活动栈的栈顶。如果不是在栈顶,就不可以重用。相反,将创建一个新的实例并压入栈顶。
    例如,一个任务的活动栈由根活动A、B、C和D组成,顺序为A-B-C-D。当一个意图到达请求类型D时,如果D是默认的"standard"模式,将产生D类的新实例且栈变为A-B-C-D-D。然而,如果D的启动模式是"singleTop ",已存在的D实例将去处理新的意图(因为它在栈顶)且栈仍然是A-B-C-D。
    如果,另一方面,到达的意图是请求类型B时,一个B的新实例将启动而不管B的模式是"standard"还是"singleTop "(因为B不是在栈顶),因此栈的结构为A-B-C-D-B。
    如前所述,"singleTask"和"singleInstance"活动仅可以被实例化一次,因此他们的实例将处理所有的新意图。一个"singleInstance"活动总是在栈顶(因为仅有一个活动在任务中),因此它总是在可以处理意图的位置。然而,一个"singleTask"活动在栈中可能有或可能没有其他活动在它上面。如果有,即它不在处理意图的位置,意图会被丢弃(即使意图被丢弃了,它的到来使任务转到并保持在前台运行)

当一个已存在的活动被请求处理一个新的意图,Intent对象将通过onNewIntent()调用传到活动。(产生启动活动的意图对象可以由getIntent()获取。)

注意到当一个活动的新实例被创建去处理新意图时,用户总是可以按返回键返回到之前的状态(之前的活动)。但是当一个已存在的活动实例去处理新意图是,用户不可以按返回键返回到意图到达之前的状态。

4、清除栈(Clearing the stack)

如果用户离开一个任务很长时间,系统将会清除根活动之外的活动。当用户再次返回到这个任务时,像用户离开时一样,仅显示初始的活动。这个想法是,一段时间后,用户可能已经放弃之前做的东西,及返回任务做新的事情。这是默认情况,有些活动属性可以用来控制和改变这个行为。

  • alwaysRetainTaskState属性
    如果在任务的根活动中这个属性被设置为"true",刚才描述的默认行为将不会发生。任务将保留所有的活动在它的栈中,甚至是离开很长一段时间。
  • clearTaskOnLaunch属性
    如果在任务的根活动中这个属性被设置为"true",只有用户离开就清除根活动之外的活动。换句话说,它与alwaysRetainTaskState截然相反。用户总是返回到任务的初始状态,甚至是只离开一会。
  • finishOnTaskLaunch属性
    这个属性类似于clearTaskOnLaunch,但是它作用于单个活动,而不是整个任务。而且它能移除任何活动,包括根活动。当它被设置为"true",任务本次会话的活动的部分还存在,如果用户离开并返回到任务时,它将不再存在。

有其他的方法强制从栈中移除活动。如果Intent对象包含FLAG_ACTIVITY_CLEAR_TOP标志,目标任务已经有一个指定类型的活动实例,栈中该实例上面的其它活动将被移除而使它置于栈顶响应意图。如果指定的活动的启动类型是"standard",它自己也将被移除出栈,且一个新的实例将被启动去处理到来的意图。这是因为当模式是"standard"时,总是创建一个新的实例去处理新的意图。

FLAG_ACTIVITY_CLEAR_TOP标志经常与FLAG_ACTIVITY_NEW_TASK一起使用。当一起使用时,这些标志的方式是定位到另一个任务中的已存在的活动并把它放到可以处理意图的位置。

5、启动任务(Starting tasks)

通过给定活动一个意图过滤器"android.intent.action.MAIN"作为指定行为(action)和"android.intent.category.LAUNCHER"指定种类(category),活动就被设置为任务的入口点了。上篇Android开发之旅:应用程序基础及组件(续)第四节Intent过滤器中我们举了这样一个例子,它将导致该活动的图标(icon)和标签(label)显示在应用程序启动器,给用户启动它或启动之后任意时候返回到它。

它的第二个功能非常重要:用户可以离开任务且之后可以返回到它。基于这个原因,两个启动模式"singleTask"和"singleInstance"标记活动总是初始化一个任务来响应意图,仅可以使用在有MAINLAUNCHER过滤器的活动中。想象一下,如果没有这个过滤器将会发生什么:一个意图启动一个"singleTask"活动,开始一个新任务,用户在任务中做一些操作。然后用户按下HOME键,任务现在退到后台运行且被主屏幕遮蔽住。而且,由于活动不在应用程序启动器中显示,用户无法再返回。

类似的困难也出现在FLAG_ACTIVITY_NEW_TASK标志。如果这个标志导致一个活动开始一个新的任务且用户按HOME键离开它,就必须要有某种方法是用户能够导航回来。一些实体(如通知管理器)总是在外部任务启动活动,从不作为他们自己的一部分,因此他们总是将带FLAG_ACTIVITY_NEW_TASK标志的意图传到startActivity()方法启动活动。如果你有活动能调用外部实体,可以使用此标志,注意用户有一个独立的方式返回到开始的任务。

如果您希望用户离开活动后就不能再回到这个活动,可以将<activity>元素的finishOnTaskLaunch属性设置为"true"。可以参见清除栈那节。

分享到:
评论
2 楼 zapldy 2010-09-26  
affinity被翻译成亲和度我觉得非常雷人,可能翻译成关联关系比较恰当一些!
1 楼 ginger985 2010-09-14  
楼主很强悍,敝人也正在研究Android,有几个问题请教下楼主
1.

如前所述,默认情况下,一个新的活动被启动到调用startActivity()方法的活动所在的任务。它被压入调用它的活动的栈中。但是,如果传递给方法的Intent对象包含FLAG_ACTIVITY_NEW_TASK标志,系统找一个不同的任务容纳活动。通常,顾名思义它表示一个新任务。但是,他并非一定如此。如果已经存在一个任务与新活动亲和度一样,该活动将启动到该任务。如果不是,则启动一个新任务。

这一段的描述中,系统找到多个与新活动有相同亲和度的任务时,该怎么办?
又或者这样问,两个任务的亲和度可以相同吗?

2.
如果一个活动的allowTaskReparenting属性为"true",它可以从启动它的任务转移到与它有亲和度并转到前台运行的任务中。例如,假设一个天气预报的活动,但选择城市是一个旅游应用程序的一部分。它与同一个应用程序中的其他活动具有相同的亲和度,且允许重新选择父活动(reparenting)。你的一个活动启动天气预报活动,因此他初始是跟你的活动属于同一个任务。但是,当旅游应用程序切换到前台运行时,天气预报活动将被重新分配和显示到该任务。

这一段的描述中,一个活动的allow...属性为true,它可以从启动它的任务转移到与它有相同亲和度且正在前台运行的任务中,是这个意思吗?
另外,天气预报的例子没太明白,对于这个例子,我的理解是这样,帮忙看一下是否有误:
  有一个天气预报的活动,它被一个选择城市的活动启动,选择城市属于旅游应用程序的一部分,而天气预报不属于,所以,当旅游应用程序正在前台运行,并且通过选择城市活动启动天气预报活动,这时,天气预报默认与选择城市处于同一个任务当中,接下来,我点击HOME按钮,启动我的一个应用程序,同时启动一个默认活动,在这个默认活动中,启动了天气预报,这时的天气预报和之前的天气预报是同一个实例吗?如果是,那么天气预报应该会从之前的任务中转移到默认活动所在的任务中,接下来,再次进入HOME,开启旅游程序,天气预报又会从现在的任务中转移到与选择城市所在的任务中,是这样的吗?

相关推荐

    Android开发之旅

    Android开发之旅:活动与任务 6 Android开发之旅:进程与线程 7 Android开发之旅:组件生命周期(一) 8 Android开发之旅:组件生命周期(二) 9 Android开发之旅:组件生命周期(三) 10 Android 开发之旅:又...

    Android开发之旅 完整版pdf

    • Android 开发之旅:活动与任务 • Android 开发之旅:进程与线程 • Android 开发之旅:组件生命周期(一) • Android 开发之旅:组件生命周期(二) • Android 开发之旅:组件生命周期(三) • Android ...

    Android开发之旅——完整版

    • Android 开发之旅:活动与任务 • Android 开发之旅:进程与线程 • Android 开发之旅:组件生命周期(一) • Android 开发之旅:组件生命周期(二) • Android 开发之旅:组件生命周期(三) • Android ...

    Android 系统开发技术课程设计 实验任务书及实验报告

    实验1构建Android开发环境和Android应用程序 实验2基本视图组件的使用(一) 实验3:基本视图组件的使用(二) 实验4:布局管理器 实验5:Intent、Activity应用 实验6:基本视图组件的使用(三) 实验7 音乐播放器 ...

    AndroidStudio移动应用开发任务教程(微课版)_PPT课件和教案.zip

    AndroidStudio移动应用开发任务教程(微课版)_PPT课件和教案.zip

    android开发期末大作业.zip

    android开发期末大作业(项目源码,任务书,实验大报告,apk文件) 大作业的要求和内容:(包括题目选择范围、技术要求、递交时间、考核方法等) 一、实验项目名称 Android手机应用开发课程大作业 二、实验目的 1....

    《Android应用程序开发教程(第2版)》教学课件02Android UI设计.pdf

    《Android应用程序开发教程(第2版)》教学课件02Android UI设计.pdf《Android应用程序开发教程(第2版)》教学课件02Android UI设计.pdf《Android应用程序开发教程(第2版)》教学课件02Android UI设计.pdf《Android应用...

    任务书基于android studio的图书管理系统的APP开发.docx

    任务书基于android studio的图书管理系统的APP开发.docx

    android开发系列美文

    Android开发:android架构 Android开发:活动与任务 Android开发:进程与线程 Android开发:应用程序基础及组件 Android开发:组件生命周期 ...

    Android应用开发任务管理器源码

    android手机应用任务管理器的源码,开源协议,初学者可以下载回去参考学习一下。

    Android应用开发常见错误与对策

    Android应用开发常见错误与对策 Android应用开发常见错误与对策 提纲 一、Android 总体框架介绍 1. Android历史 ...五、Android开发文化探讨 1. Android Design 文化 2. 做一个本分的APP 六、开放式讨论

    《Android应用开发》开放实验项目总结报告-模板.doc

    " "熟练使用Android开发的集成开发环境ADT或Android Studio; " "掌握如何合理运用Android应用框架API开发出相对较完整的工具类应用 " "3.开放实验项目的内容(可多页) " "实验内容: " "根据自己选择的应用程序...

    Android开发案例驱动教程 配套代码

    9.3.3 任务与标志 196 9.4 Android系统内置Intent 199 本章小结 201 第10章 数据存储 203 10.1 健康助手案例 203 10.2 Android数据存储概述 205 10.3 本地文件 205 10.3.1 访问SD卡 207 10.3.2 访问应用文件...

    Android入门到精通-实训任务1-搭建Android开发环境

    Android入门到精通-实训任务1-搭建Android开发环境

    Android高级应用开发教学视频-Android高级应用开发.z05

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z19

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android 7最近任务栏UI,RecentsActivity

    Android 7最近任务栏UI,RecentsActivity。DeckView重新编译,更方便代码运行,2022年重新编译后的代码,简洁明了。

    Android-TimeTask是一个轻量简洁的定时任务队列框架

    TimeTask是一个轻量简洁的定时任务队列框架,专注处理多组任务分发工作 TimeTask内部的实现时基于AlarmManager 广播,在任务与系统api中间做了较好的封装

    Android开发入门经典pdf

    系统的、循序渐进的学习Android开发所需的知识 n 第一部分:Android的入门基础 ...包括:Android开发的核心组件介绍,Intent和Intent Filter,资源与国际化, 安全和权限,应用、任务、进程和线程,ADB的使用等

    android开发十个案例打包下载

    android移动开发10个案例源码: 1 图片浏览器 2 文件浏览器 3 通讯录 4 任务管理器 5 音乐播放器 6 天气预报 7 多媒体播放器 8 短信语音播报 9 手机远程监控 10 贪吃蛇游戏

Global site tag (gtag.js) - Google Analytics