Activity和 Task是 Android Application Framework架构中最基础的应用,开发者必须清楚它们的用法和一些开发技巧。本文用大量的篇幅并通过引用实例的方式一步步深入全面讲解它们的基础原理(underlying principles)和架构(mechanisms),例如Navigation Multitasking、activity re-use、intents和 activity stack等„大部分与其相关的应用模块。重点讲解开发过程中如何更准确的体现用户交互性的便捷和高效,同时也帮助分析Designers和 Developers在开发期间所要面对的问题。文中涉及到的实例有一部分是属于平台自带的 application(例如:拨号程序等),另外也有 Google产品线中的一些有代表性的应用(例如:Google Map等)。建议大家亲自利用 Emulator或者 Android-powered device测试实例中的效果,这样可以帮助更加清晰的理解一些模块的含义。(注意:可能会因为硬件对于某些功能无法提供支持,所以有一些实例可能无法在你的测试机中正常浏览) 。
首先需要清楚一些基础模块:
——Applications
——Acitivities
——Activity Stack
——Tasks
以上这四个模块对于理解这篇文章非常重要,下边就来逐一的简单介绍其具体的含义和用法(也可以通过其链接直接查看官方文档)。
任何一个Android Application基本上是由一些Activities组成,当用户与应用程序交互时其所包含的部分Activities具有紧密的逻辑关系,或者各自独立处理不同的响应。这些 Activities捆绑在一起成为了一个处理特定需求的Application, 并且以“.apk”作为后缀名存在于文件系统中。Android平台默认下的应用程序 例如:Email、Calendar、Browser、Maps、Text Message、Contacts、Camera和Dialer等都是一个个独立的Apps。
上边已经提到 Activities是构成 Applications的主要组成部分,其实可以更为具体的理解为Application仅仅是一个抽象的标签,它将系统内一部分Activities关联在一起,协同完成用户的特定需求。安装Application的过程也可以简单理解为将其所包裹的Activities导入到当前的系统中,如果系统中已经存在了相同的Activities,那么将会自动将其关联,而不会重复安装相同的 Activities,避免资源的浪费。Application卸载的过程也会检查当前所关联的Activities是否有被其它 Application标签所关联,如果仅仅是提供当前的Application使用,那么将会彻底被移除,相反则不做任何操作。
用户与 Application的交互行为大部分都是通过 GUI来完成,在 Android平台可以有两种方式定义 GUI,其中可以利用 XML来预置静态的 GUI元素,或者在 Activity类的内部动态定义 GUI元素。这两种不同的方法都是由Activity作为驱动和响应用户交互事件的主体。当启动Application之后,至少需要一个包含有 GUI信息的 Activity实例被创建。
Activity的主体包括两个主要部分,其中一个是 Content(data),另外一个是响应用户交互事件的行为。列举一个 Dialer例子的截图,其中包括四个部分:Dialer主界面、通讯录、查看联系人信息和添加新联系人。 下面列举了更多比较有代表性的Applications和其所包含的Activities:
Email – activities to view folders, view list of messages, view a message, compose a message, and set up an account
Calendar – activities to view day, view week, view month, view agenda, edit an event, edit preferences, and view an alert
Camera – activities for running the camera, viewing the list of pictures, viewing a picture, cropping a picture, running the camcorder, viewing the list of movies, and viewing a movie
Game – one activity to play the game, typically another for setup
Maps – one activity to view a location on a map, a second for lists (such as turn list or friend list), and a third for details (friend location, status, photo)
Application基本上是由四个模块组成:Activity、Service、Content Provider 和 Broadcast Receiver,其中Activity是实现应用的主体。
Activities可以被看作为是独立存在于系统资源中,而且是作为实现具体应用的主体,Task将一些Activity关联起来实现一个更复杂的应用,单独或者多个Tasks可以被定义为一个Application。
通常实现一个Task都会存在一个Root Activity,但并不是所有情况都如此,通过Application launcher、Home screen 的快捷方式或者 由 “Recent Tasks”(长时间按住Home键) 最近使用过的Task记录中启动。当从一个Activity中启动另外一个Activity时,Back键将作用于返回前一个Activity,与此同时新开启的Activity将被添加到Activity Stack中。
这里有两个被表示为Task的例子:
发送带有附件的邮件查看YouTube视频,并且通过Email的方式共享给其他联系人。
- Interrupting the Task
这是Task一个非常重要的特性,用户可以实时中止当前为完成的Task,新开启一个不同的Task,当新Task完成操作后,依然可以返回当上一次中止的Task继续完成余下操作。这个特性大大方便了同时运行多个Tasks,并且可以方便的在他们之间切换。这里有两种方式可以从当前Task跳转为其它Task(应用这两种方式切换Task,都允许返回到Task最初中止前的状态)。
系统抛出一个Notification,当前Task会被终止,跳转为Notification的Task。
用户强制中止
当然,除了这两种方式以外,还有另外一个特殊情况,算作为第三种方式来启动一个新的Task:Activity本身被定义为一个Task。例如: Maps和Browser就是属于第三种情况的Application,通过邮件中的一个地址来启动Maps Activity作为一个新的Task,或者通过邮件中的链接启动Browser来启动一个新的Task。当处在这种情况下,Back按键被触发后,将返回到上一个Task(邮件),因为这些新的Tasks并不是通过Home Screen中的Application launcher或者快捷方式来启动。
-Home:
利用Home取代Back返回的方式,当前Activity将被切换到Background,而不是被Destroied。这样的好吃是可以暂时保留这个Activity的State信息,当再次通过Application launcher或者快捷方式启动时,可以返回到最后离开的状态。对比在Back中引用的例子,当再次由Home返回到Activity时,将会看到最后一次操作所记录的Scroll状态,而不是默认的初始位置。
Exception(例外情况)
前边列举了两种典型的情况,同时还存在一些例外的情况,某些Activity从Background被“召唤”到foreground之后依然是相当于重新创建了新实例,其有区别于前边所论述的结果。即便是暂时保存在Background模式下(没有被Destroied),其State数据也将丢失。例如:Contacts 和 Gallery 等。当用户启动了Contact应用程序,并点选某个条目查看详细信息,如果通过Home键返回后,再次重复启动Contact应用程序时,看到的并不是之前所打开的特定条目的详细信息,而是初始的默认界面。这个例子说明不是所有情况下通过Home键返回后都可以保存当前Activity的State信息。
另外一种是与Back键有关的特殊情况。前边提及到大部分的Activity通过Back键返回到Home Activity时,其自身将被彻底销毁,默认情况下Activity响应Back按键的方法被定义了Destroy行为。但对于某些特别情况,开发者可以根据需求将相应Back按键事件的行为重新“override”,撤消默认的Destroy行为。音乐播放器是与其相关的一个典型应用,当用户在播放器的Root Activity中触发Back按键后,转为Background模式下继续播放当前的音乐,同时Home Activity转为Foreground。
- 利用Messaging扩展Gallery共享功能
用户通过Gallery查看当前系统中的图像资源,每次单独打开一幅图像资源都可以通过Menu -> Share将当前的资源以附件形式插入新创建的Messaging中,并且以正常发送信息的方式将其共享给收件人。如果取消当前的共享行为,只需要通过Back按键返回到Gallery Activity。相比较前一个例子的区别在于,Message Activity完成发送或者被取消操作,其不会返回任何信息。
以上两个例子分别讲解了利用一系列的Activities来完成某一项需求,并且它们都调用了外部的Application资源。
Replacing an Activity
目前要介绍的内容是关于在不同的Applications中,有相同Intent filter属性的Activities可相互间替换,这对于习惯Windows等操作系统的用户比较不容易理解。其实如果您足够细心,就可以发现之前的例子中有关于这里所提及情况。
通常遇到这种情况发生时,一般都是因为外部具有相同功能的Activity A 在处理问题的能力方面要优于当前Application中默认的操作行为Activity B,系统会抛出一个可供选择的对话框,用户根据主观判断来选择最优的方式处理当前任务。通过一个比较容易理解的实例来说明整个过程,建议“动手能力强”的同学可以通过模拟器亲自尝试。
例如:用户在当前系统下加载了最新的Phone Ringtone Activity,取名为Rings Extended。如果用户通过Setting -> Sounds&Display -> Phone Ringtone 来设置当前的铃音属性时,将会弹出一个包含有系统默认的Phone Ringtone Activity 和最新加载的Rings Extended两种可供选择的操作应用,同时在对话框中还提供了一种可以直接启动系统默认的操作方式选项。如果用户选择了Rings Extended,那么其将会被载入当前的线程中替代原有的默认操作行为,可以根据下面的图示来增强理解。
多任务同时运行(Multitasking)
在之前的板块有专门提到关于Home和Back两种切换到Home Screen的方法和它们之间的差异性,这个章节将会重点涉及到系统可以同时处理多个实时运行的任务。如果用户正处于某个Application A开启状态时,通过Home按键切换回Home Activity的同时保留了此前Application A运行的状态信息,可以开启新程序的同时,也可以再次将Application A切换回Foreground。
最后,退出当前Calender activity返回到Home,再次通过Maps图标将其处在Background状态的实例切换到Foreground。
通过上边的例子看出用户通过Application Launcher同时运行多个Tasks,代表系统具备多任务处理机制 – Running multiple tasks。
启动Application的两种不同方式
每个App都需要提供至少一个Entry point(翻译成“入口点”有点别扭,干脆保留原样)供用户或者系统调用其所关联的Activities,Application launcher中的小图标就是每个单独App的Entry Point。另外App也可以相互间通过Activity作为Entry Point来启动,可以将App所包含的每个Activity看作为潜在的Entry point。
系统中的Phone Application同样具有两个Entry Points:Contacts和Dialer。下边的图示中可以了解到用户通过Application launcher启动Contacts Activity,选择其中某一个联系人之后,调用Dialer Activity拨打其所提供的电话号码。
Intents
在现实世界中大家每时每刻都会与周围的环境发生互动,这个互动的过程首先要确定一种意识,例如:感觉到口渴,需要水分补充。这种意识会引导自己以习惯的方式解决口渴问题,采用的方式可以多种多样,吃冰淇淋、喝水、嚼树叶等。类似于口渴的意识形态被抽象为Intent,并将其看作是一种对象,这就是Android响应“意识”的方式。
在Android平台上,用户的操作行为是由各种不同的事件组成,系统会将每个事件都抽象为Intent对象,寻找解决这项需求的具体方法。抽象的Intent对象有两种形式,第一种是“明确”的Intent(Explicit Intent),在初始化的时候已经为这个Intent关联了特定的Activity。第二种是“不明确”的Intent(Implicit Intent),代表这个Intent没有明确关联Activity,当它被抛出后,系统在众多Activities中根据Intent filter来寻找与其匹配的处理方法。如果存在多个结果,用户可以根据需要选择合适的处理方法。
引用一个具体的例子,单击一个mailto:[email protected]链接后,这个被抛出的Intent属于 Implicit Intent ,系统抓取了解决这个Intent的结果,将所有的结果供用户选择(Gmail或者Email):
下边给出更多系统默认的Intent关联列表:
View the list of contacts – resolves to a contact list viewer activity
View a particular contact – resolves to a contact viewer activity
Edit a particular contact – resolves to a contact editor activity
Send to a particular email – resolves to an email activity
Dial a phone number – resolves to a phone dialer activity
View the list of images – resolves to an image list viewer activity
View a particular image – resolves to an image viewer activity
Crop a particular image – resolves to an image cropper activity
Intent对象包含两个元素:
1)Action :例如 查看、编辑、拨打电话、查看图像资源等等。
2)Data:提供给某种行为的具体数据。加工果汁饮料,需要提供水果(黑心店除外)。
参照官网的解释:Intent Class 和 Intent Filters。
Tasks相互间切换
依然是应用实例来说明这个切换的过程。在这个例子中,用户编辑一个短消息,并且插入图像附件,但是在发送之前启动Calendar,随后切换回短消息编辑界面,最后发送信息。
1)启动第一个Task:Messaging App,Home > Messaging > New Message > Menu > Attach > Picture。插入图片的步骤需要调用Gallery Activity,它是一个独立的外部程序。
接下来启动另外一个 Task,由于没有直接从当前的 Activity运行 Calendar,所以需要切换到Home。
2)启动另外一个 Application(Calendar):Home > Calendar
查看Calendar完成后,将 Messaging由 Background切换到 Foreground模式,其中还包括了添加附件,并最终发送消息
这个是pdf的下载地址:http://download.csdn.net/detail/jwzhangjie/6402219