1、应用程序基础1应用程序基础摘要Android 应用程序使用 Java 编程语言开发。aapt 工具把编译后的 Java 代码连同应用程序所需的其他数据和资源文件一起打包到一个 Android 包文件中,这个文件使用.apk 作为扩展名。此文件是分发并安装应用程序到移动设备的载体;是用户下载到他们的设备的文件。单一.apk 文件中的所有代码被认为是一个应用程序。从多个角度来看,每个 Android 应用程序都存在于它自己的世界之中:1 默认情况下,每个应用程序均运行于它自己的 Linux 进程中。当应用程序中的任何代码需要被执行时,Android 启动此进程,而当不再需要此进程并且其它应用程序又
2、请求系统资源时,则就关闭了这个进程。 2 每个进程都有其独有的虚拟机(VM) ,所以应用程序代码与所有其它应用程序代码是隔离运行的。 3 默认情况下,每个应用程序均被赋予一个唯一的 Linux 用户 ID,并加以权限设置,使得应用程序的文件仅对此用户及此应用程序可见尽管也有其它的方法使得这些文件同样能为其他应用程序所访问。 1.1 应用程序组件Android 的一个核心的特性就是一个应用程序可以使用其它应用程序的元素(如果那个应用程序允许的话) 。例如,如果你的应用程序需要显示一个图片卷动列表,而另一个应用程序已经开发了一个合用的而又允许别的应用程序使用的话,你可以直接调用那个卷动列表来完成工
3、作,而不用自己再开发一个。你的应用程序并没有吸纳或链接其它应用程序的代码。它只是在有需求的时候启动了其它应用程序的那个功能部分。 为达到这个目的,系统必须能够在一个应用程序的任何一部分被需要时启动一个此应用程序的进程,并将那个部分的 Java 对象实例化。因此,不像其它大多数系统上的应用程序,Android 应用程序并没有为应用程序提供一个单独的入口点(比如说,没有 main()函数) ,而是为系统提供了可以实例化和运行所需的必备组件。一共有四种组件类型: (1)Activity 应用程序基础2activity 是为用户操作而展示的可视化用户界面。例如,一个 activity可以展示一个菜单项
4、列表供用户选择,戒者显示一些包含说明文字的照片。一个短消息应用程序可以包括一个用于显示要发 2 送消息到的联系人列表的activity,一个给选定的联系人写短信的 activity 以及翻阅以前的短信或改变设置的其他 activity。尽管它们一起组成了一个内聚的用户界面,但其中每个activity 都不其它的保持独立。每一个都实现为以 Activity 类为基类的子类。一个应用程序可以只有一个 activity,戒者,如刚才提到的短信应用程序那样,包含很多个。每个 activity 的作用,以及有多少个 activity,当然是取决于应用程序及其设计的。一般情况下,总有一个应用程序被标记为用
5、户在应用程序启动的时候第一个看到的。从一个 activity 转向另一个靠的是用当前的 activity 启动下一个。 每个 activity 都被给予一个默认的窗口以进行绘制。一般情况下,这个窗口是满屏的,但它也可以是一个小的位于其它窗口之上的浮动的窗口。一个activity 也可以使用附加的窗口例如,一个在 activity 运行过程中弹出的供用户响应的对话框,这是一个当用户选择了屏幕上特定项目后显示的必要信息的窗口。 窗口显示的可视内容是由一系列层次化 view 构成的,这些 view 均继承自 View 基类。每个 view 均控制着窗口中一块特定的矩形区域。父级 view 包含并组织
6、其子 view 的布局。叶节点 view(位于层次结构最底端)在它们控制的矩形区域中进行绘制,并对用户直达其区域的操作做出响应。因此,view 是activity 与用户进行交互的界面。例如,view 可以显示一个小图片,并在用户指点它的时候产生动作。Android 有一些预置的 view 供开发者使用包括按钮、文本域、滚动条、菜单项、复选框等等。 view 的层次结构是由 Activity.setContentView() 方法放入 activity 的窗口之中的。content view 是位于层次结构根位置的 View 对象。 (参见独立的用户界面文档以获取关于 view 及层次结构的更
7、多信息。 ) (2) Service service 没有可视化的用户界面,而是在一段时间内在后台运行。例如,一个 service 可以在用户做其它事情的时候在后台播放背景音乐、从网络上获取数据或者计算一些东西并提供给需要这个运算结果的 activity 使用。每个service 都继承自 Service 基类。 一个媒体播放器播放播放列表中的曲目是一个不错的例子。播放器应用程序可能有一个或多个 activity 来给用户选择歌曲并进行播放。然而,音乐播放应用程序基础3这个任务本身丌应该由任何 activity 来处理,因为用户的期望即使在他们离开播放器的应用程序而已经在开始做别的事情时,音乐
8、仍然在继续播放。为达到这个目的,媒体播放器 activity 可以启动一个运行于后台的 service 服务。系统将在这个 activity 不再显示于屏幕后,仍维持音乐播放的 service 的运行。 连接至(绑定到)一个正在运行的 service(如果 service 没有运行,则启动之)是可能的。连接之后,你可以通过那个 service 暴露出来的接口不service 进行通讯。对于音乐 service 来说,这个接口可以允许用户暂停、回退、停止以及重新开始播放。 如同 activity 和其它的组件一样,service 服务运行于应用程序进程的主线程内。所以它不会对其它组件或者用户界面
9、有任何的妨碍作用,它们一般会派生一个新线程来执行一些时间消耗型任务(比如音乐回放和网络下载) 。参见稍后的进程和线程介绍。 (3) BroadcastReceiver broadcast receiver 是一个与注于接收广播通知信息,并做出相应处理的组件。许多广播是由系统代码产生的例如,通知时区改变、电池电量低、拍摄了一张照片或者用户改变了语言选项。应用程序也可以发起广播例如,通知其它应用程序一些数据已经下载到设备上并处于可用状态。 一个应用程序可以拥有任意数量的 broadcast receiver,以对所有它认为重要的通知信息予以各种响应。所有的 receiver 均继承自 Broadc
10、astReceiver基类。 broadcast receiver 没有用户界面。然而,它们可以启动一个 activity或者 service 来响应它们收到的信息,当然也可以使用 NotificationManager来通知用户。通知可以用多种方式来吸引用户的注意力闪动背光灯、震动设备、播放声音等等。通知一般是在状态栏上放一个持丽的图标,用户可以点击打开它并获取所要消息。 (4)Contentprovider content provider 将一些特定的应用程序数据供给其它应用程序使用处理。数据可以存储于文件系统、SQLite 数据库或其它有意丿的方式。content provider 继
11、承于 ContentProvider 基类,实现了一套使得其他应用程序能够检索和存储它所管理的类型数据的标准方法。然而,应用程序并不直接调用返些方法,而是使用一个 ContentResolver 对象,调用它的方法作为替代。ContentResolver 可以与任何 content provider 进行会话;与其合作对任何相关的进程间通讯进行管理。 参阅独立的 Content Providers 文档以获得更多关于使用 content 应用程序基础4provider 的信息。 每当出现一个需要被特定组件处理的请求时,Android 会确保那个组件的应用程序进程处于运行状态,必要时会启动它,并
12、确保那个组件的一个合适的实例可用,必要时会创建那个实例。 1.2激活组件:intent当接收到 ContentResolver 发出的请求后,content provider 被激活。而其它三种组件activity、service 和 broadcast receiver,被一种叫做intent 的异步消息所激活。intent 是一个保存着消息内容的 Intent 对象。对于 activity 和 service 来说,它指明了所请求的操作名称,并指定了用来操作的数据的 URI 和其它一些信息。例如,它可以承载一个对一个 activity 的请求,让它为用户显示一张图片,或者让用户编辑一些文本
13、。而对于 broadcast receiver 来说,Intent 对象指明了所通报的操作。例如,它可以对所有感兴趣的对象通报照相按钮被按下。 对于每种组件来说,激活的方法也是不同的: 1 通过传递一 IntentContext.startActivity()Activity.startActivityForResult(以启动(或指定新工作给)另外一个activity。相应的 activity 可以通过调用自身的 getIntent() 方法来查看并且激活它的 intent。Android 通过调用 activity 的 onNewIntent()方法来传递给它随后的任何 intent。一个
14、 activity 经常启动另一个 activity。如果它期望它所启动的那个activity 返回一个结果,它会调用 startActivityForResult()而不是startActivity()。例如,如果它启动了另外一个 activity 以使用户挑选一张自己的照片,它也许想知道哪张照片被选中了。其结果将会被封装在一个Intent 对象中,并传递给发出调用的 activity 的 onActivityResult() 方法。 2 通过传递一个 Intent 对象至 Context.startService()以启动一个service(或向正在运行的 service 给出一个新的指令
15、) 。Android 调用此service 的 onStart()方法并将 Intent 对象传递给它。 与此类似,一个 intent 可以被传递给 Context.bindService()以建立一个处于调用组件和目标 service 乀间的活动连接。此 service 会通过 onBind() 方法的调用来获取此 Intent 对象(如果此 service 尚未运行,bindService()会先启动它) 。例如,一个 activity 可以建立一个不前述的音乐回放 service的连接,这样它就可以提供给用户一些途径(用户界面)来控制回放。这个应用程序基础5activity 可以调用 b
16、indService()来建立此连接,然后调用 service 中定之的方法来控制回放。 稍后的远程方法调用一节有关于如何绑定至一个 service 的更多细节。 3 应用程序可以通过传递一个 Intent 对象至 Context.sendBroadcast() ,Context. sendOrderedBroadcast(), 以及 Context.sendStickyBroadcast()和其它类似方法来发起一个广播。Android 会调用所有对此广播有兴趣的broadcast receiver 的 onReceive()方法,将此 intent 传递给它们。 1.3 关闭组件conten
17、t provider 仅在响应来自 ContentResolver 的请求时处于不同活动状态。而 broadcast receiver 仅在响应一条广播信息的时候处于各种活动状态。所以没有必要去显式地关闭这组件。 而 activity 则不同,它提供了用户界面。只要会话依然持续,无论会话过程有无空闲,activity 同用户进行长时间会话且可能一直处于活动状态。与此相似,service 也会在很长一段时间内在后台保持运行。所以 Android 为关闭activity 和 service 提供了一系列有序的方法。 activity 可以通过调用自身的 finish()方法来关闭。一个 activ
18、ity 可以通过调用 finishActivity()方法来关闭另外一个 activity(它用startActivityForResult() 启动的) 。 service 可以通过调用自身的 stopSelf()方法,或调用 Context.stopService()来停止。 系统也会在组件不再被使用的时候戒者当 Android 必须为更多的活动组件回收内存时关闭它。稍后的组件的生命的周期一节,将对这种可能性及结果进行更详细的介绍讨论。 1.4 manifest文件当 Android 启动一个应用程序组件之前,它必须知道那个组件是存在的。因此,应用程序会在一个被打包到 Android 包中
19、的 manifest 文件中声明它的组件,.apk 文件还将涵括应用程序的代码、文件以及其它资源。 manifest 文件是一个结构化的 XML 文件,而且对于所有应用程序,文件名总是 AndroidManifest.xml。除了声明此应用程序各个组件,它会做很多其他工作,比如指明应用程序所需链接到的库的名称(除了默认的 Android 库外)应用程序基础6以及标出应用程序期望获得的各种权限。 但 manifest 文件最重要的任务是向 Android 报告此应用程序的各个组件。丼例说明,一个 activity 可能声明如下: 元素的 name 属性指定了实现此 activity 的 Acti
20、vity 子类。icon 和 label 属性指向包含展示给用户的此 activity 的图标和标签的资源文件。 其它组件也以类似的方法声明 元素用于声明 service, 元素用于声明 broadcast receiver,而 元素用于声明 content provider。未在 manifest 文件中进行声明的 activity、service以及 content provider 将不为系统所见,从而也就永不会被运行。然而,broadcast receiver 既可以在 manifest 文件中声明,也可以在代码中动态创建(为 BroadcastReceiver 对象) ,并以调用 C
21、ontext.registerReceiver()的方式注册至系统。 1.5 Intent过滤器一个 Intent 对象可以显式地指定一个目标组件。如果进行了返种指定,Android 会找到这个组件(基于 manifest 文件中的声明)并激活它。但如果intent 没有显式地指定一个目标,Android 就必须找到最合适的组件来响应此intent。这个过程是通过比较 Intent 对象和所有潜在目标的 intent 过滤器完成的。组件的 intent 过滤器会通知 Android 它所能处理的 intent 类型。如同应用程序基础7组件的其它必要信息一样,这些 intent 过滤器是在 ma
22、nifest 文件中进行声明的。返里有一个对先前例子的扩展,其中加入了针对 activity 的两个 intent过滤器: 示例中的第一个过滤器action“android.intent.action.MAIN”和category“android.intent.category.LAUNCHER”的组合是常见的一个。它标明了此 activity 应该在应用程序启动器中显示,就是用户在屏幕上看到的此设备上可供启动的应用程序的列表。换句话说,这个 activity 是应用程序的入口点,是用户在启动器中选择运行这个应用程序后所见到的第一个activity。 第二个过滤器声明了此 activity 在
23、一种特定类型的数据上可以执行的操作。一个组件可以拥有任意数量的 intent 过滤器,每个都声明了一套不同的功能。如果组件没有包含任何过滤器,它只能被显式地指明作为目标组件的intent 激活。 对于在代码中创建并注册的 broadcast receiver 来说,intent 过滤器将被直接实例化 IntentFilter 为对象。其它所有的过滤器都在 manifest 文件中应用程序基础8设置。 1.6基于 XML的布局虽然纯粹通过 Java 代码在 activity 上创建和添加部件,在技术上是可行的,我们在第 4 章中做的一样,更常见的方法是使用一种基于 XML 的布局文件。动态的小部
24、件实例保留更多,情况复杂,小工具在编译时不为人所知(例如,在数据检索了互联网基础上将单选按钮填充柱。考虑到这一点,现在是时候打破 XML 来学习如何用此种方式来布置Android activities。正如其名称所示,一个基于 XML 的布局是一个关系到每个规格的小部件,和他们的容器(更多关于此内容的在第 7 章)编码的 XML 格式。具体来说,Android 认为基于 XML 的布局是资源,因此布局的文件存储在 res /在你的Android 项目布局目录中。每个 XML 文件包含一个指定的部件和容器布局元素树,一种意见认为构成层次。对 XML 元素的属性,描述一个部件应如何看或者一个容器应
25、如何运转。例如,如果一个按钮元素。有一个 Android 的属性值:文字样式=“bold” ,这意味着该文本出现在按钮的表面应该是呈现一个粗体字体样式.Android 的 SDK 中附带一个使用的布局的工具(aapt) 。这个工具应自动调用你的 Android 工具链(例如,Eclipse 中,Ants build.xml) 。作为一个开发人员,尤其重要的是,在您的项目中 aapt 生成 R.java 源文件,让您能在那些布局中直接从 Java 代码中获取布局和部件。XML 作为一个 GUI 定义格式是越来越流行普遍。微软的 XAML,Adobe 的 Flex,和 Mozilla 的 XUL 都采取 Android 类似的方法:把布局细节放在一个 XML 文件和把编程智慧资料放在源文件(例如,XUL 中的 JavaScript) 。许多不太知名的图形用户界面框架,如 ZK,还使用视图定义的 XML。而“随大流”并不一定是最好的政策,但他们有优势帮助从任何其他 XML 为中心的观点描述语言轻松入Android。应用程序基础9Application Fundamentals1