首页 > 代码库 > Android开发-API指南-应用程序开发基础
Android开发-API指南-应用程序开发基础
Application Fundamentals
英文原文:http://developer.android.com/guide/components/fundamentals.html
采集日期:2014-04-16
搬迁自原博客:http://blog.sina.com.cn/s/blog_48d491300101h41p.html
在本文中
- 应用程序组件
- 激活组件
- Manifest 文件
- 声明组件
- 声明应用程序的需求
- 应用程序资源
Android 应用程序是用 Java 语言编写的。Android SDK 工具软件会把代码—连同数据、资源文件—一起编译并放入 APK:Android 包中,这是个后缀为.apk
的打包文件。APK 文件里包含了 Android 应用程序需要的所有内容,同时也是在 Android 设备上安装该应用程序所用到的安装文件。
安装完成后,每个 Android 应用程序就独立运行于各自的安全沙盒中:
- Android 操作系统是一个多用户的 Linux 系统,其中的每个应用程序都是一个独立的用户。
- 默认情况下,系统将给每个应用程序赋予一个唯一的 Linux 用户 ID(该 ID 仅供系统使用,对应用程序是不可见的)。系统将对应用程序内的所有文件分配权限,只有赋予该应用程序的用户 ID 才能访问这些文件。
- 每个进程都拥有自己的虚拟机(VM),因此不同应用程序的代码是相互独立运行的。
- 默认情况下,每个应用程序运行于自己的 Linux 进程中。每当需要运行应用程序的某个组件时,Android 就会启动进程,并在不再需要时或必须为其他应用程序腾出内存时关闭进程。
这样,Android 系统实现了最小权限原则。也就是说,每个应用程序默认只访问必要的组件。这就建立了一种非常安全的环境,这里的应用程序无法访问未授权的系统内容。
不过,应用程序还是有很多方法与其他应用程序共享数据或访问系统服务的:
- 可以让两个应用程序共享同一个 Linux 用户 ID,这样它们就可以相互访问文件了。为了节省系统开销,用户 ID 相同的应用程序还可以运行于同一个 Linux 进程中,并且共享同一个 VM(这些应用程序还须由同一个证书签名)。
- 应用程序可以申请访问设备数据的权限,诸如用户通讯录、短信、可挂载存储(SD卡)、摄像头、蓝牙等等。所有应用程序的权限都必须在安装时由用户授权。
上面简述了 Android 应用程序是如何在系统中运行的。本文剩余部分将介绍:
- 建立应用程序所需的主要组件。
- 用于声明组件和所需硬件的 manifest 文件。
- 与代码分离的资源,使得应用程序可以根据各种硬件配置来友好地展示界面。
应用程序组件
组件(component)是搭建 Android 应用程序的基础部件。每个组件都是一个独立的入口点,系统可以通过它们进入你的应用程序。不是每个组件都是供用户使用的入口,有些组件是相互依存的,但每个组件都作为实体运行并发挥特定的作用—每个组件都是唯一的组成部分,为应用程序的整体表现出力。
应用程序组件分为四种类型。每类组件实现不同的目标,拥有各不相同的从创建到消亡的生命周期。
下面介绍这四种类型的应用程序组件:
- Activity
- Activity代表一个包含了用户界面的屏幕(窗口)。比如,一个 email 应用程序可能会包含一个显示未读邮件列表的 Activity、一个撰写邮件的 Activity 及一个阅读邮件的 Activity。虽然该 email 应用程序中由多个 Activity 一起构成了完整的用户体验,但是每个 Activity 都是相互独立的。因此,另一个应用程序可以启动其中任意一个 Activity(如果该 email 应用程序允许的话)。例如,为了让用户能分享照片,某个拍照应用可以启动该 email 应用程序的 Activity 来撰写一封新邮件。
Activity 实现为
Activity
对象的一个子类,更多内容请参阅开发指南中的Activity。 - 服务
- 服务 是一种后台运行的组件,用于执行运行时间较长的操作,或是为远程进程提供服务。服务不提供用户界面。例如:当用户使用其他应用程序时,服务可以在后台播放音乐,或者可以通过网络下载数据,这些都不需要用 Activity 与用户进行交互。其他组件,比如 Activity,可以启动并运行服务,也可以与之绑定以便交互。
服务是作为
Service
对象的子类来实现的,你可以在开发者指南的Services 中了解更多内容。 - Content Provider
- Content Provider 管理着某个可共享的应用程序数据集。你可以把数据保存在文件系统、SQLite 数据库、Web、或其他任何应用程序可访问的持久性存储上。通过 Content Provider,其他应用程序可以查询甚至修改数据(如果 Content Provider 允许的话)。例如,Android 系统就提供了一个管理用户通讯录信息的 Content Provider。这样,任何拥有适当权限的应用程序就都可以查询该通讯录 Content Provider 里的某部分数据(比如
ContactsContract.Data
),以便读写某个联系人的信息。对于读写应用程序私有的数据而言,Content Provider 也很有用。比如,例程 Note Pad 就使用了一个 Content Provider 来保存笔记。
Content Provider 是作为
ContentProvider
的子类实现的,且必须实现一组标准的 API,以便其他应用程序能提交事务。详情请参阅开发者指南的 Content Providers 部分。 - 广播接收器
- 广播接收器 是一种响应系统级广播信息的组件。很多广播都来源于系统 — 比如屏幕已关闭、电池电量低、拍了一张照片等消息通知。应用程序也可以发起广播 — 比如通知另一个程序所需数据已经下载到本地设备并已可用。尽管广播接收器不显示用户界面,但在广播事件发生时它可以创建一条状态栏通知来通知用户。不过,更多时候,广播接收器仅仅是为其他组件充当“入口”,用于完成很少量的工作。例如,它可以初始化一个服务,根据广播事件来完成某些任务。
广播接收器是作为
BroadcastReceiver
对象的子类实现的,每条被分发的广播都是一个Intent
对象。更多信息请参阅BroadcastReceiver
类。
Android 系统有一条独特的设计,就是任何应用程序都能启动其他应用程序的组件。例如,假设你要让用户使用摄像头拍照,而其他应用程序已经实现这一功能,你的应用程序就可以直接使用,而不需要自行开发一个 Activity 来完成拍照功能。你甚至不必包含或链接摄像头应用的代码,而只要启动摄像头应用中的拍照 Activity 即可。拍摄完成后,照片甚至都会直接返回给你的应用程序以便使用。对于用户而言,摄像头应用就像是你的应用程序中的一部分一样。
当启动一个组件时,系统会启动相关应用程序的进程(如果该程序还未运行的话),并且实例化组件所需的类。例如,如果你的应用程序启动了摄像头应用中的拍照 Activity,则此 Activity 运行于摄像头应用的进程中,而不是你的应用程序的进程。因此,与其他大多数系统不同,Android 应用程序不存在一个单一的入口点(比如没有main()
函数)。
因为系统把每个应用程序都放入相互独立的进程中运行,文件权限限制了对其他应用的访问,你的应用程序不可能直接启动其他应用的组件。但是 Android 系统可以这么做。因此,要激活其他应用的组件,你必须向系统分发一条消息,其中设定了要激活某个组件的 Intent。然后,系统就会为你启动该组件。
激活组件
在四种类型的组件中,有三种 — Activity、服务和广播接收器 — 都是由名为 Intent 的异步消息激活的。在运行时,Intent 与某个组件相互绑定(你可以将它们看作是来自其他组件的执行某个操作的请求消息),无论此组件是属于你的应用自身还是其他应用。
Intent 是用 Intent
对象创建的,定义了一个激活某个或某类组件(Intent 分别是显式或隐式的)的消息。
对于 Activity 和服务而言,Intent 定义了所要执行的操作(比如:“查看”或“发送”信息),并可以指定所操作数据的 URI(所要激活的组件可能会需要知道)例如,某 Intent 可能会发送一个请求,要让某个 Activity 显示一张图片或者打开一个网页。某些时候,你要启动一个 Activity 并接收结果,这时 Activity 还要在 Intent
中返回结果(例如,你可以提交一个 Intent 来让用户选取某个联系人并返回数据 — 返回的 Intent 包含了一个指向联系人信息的 URI)。
对于广播接收器而言,Intent 只是简单地定义了要广播的消息(例如,一条表示电量不足的广播可以仅包含一个“电量不足”字符串。
剩下一类组件 Content Provider,不是由 Intent 激活的。而是由 ContentResolver
发出的请求启动。Content Resolver 负责处理 Content Provider 所有的事务,因此需要执行事务的组件不必去调用ContentResolver
对象的方法。这就在 Content Provider 和请求数据的组件之间建立一个抽象层(处于安全考虑)。
每种组件都有各自的激活方法:
- 通过把
Intent
传入startActivity()
或startActivityForResult()
(如果需要返回结果的话),可以启动某个 Activity (或者让它执行某些新任务)。 - 通过把
Intent
传入startService()
,你可以启动某个服务(或者给已有的服务发布新的指令)。或者可以把Intent
传入bindService()
,以绑定某个服务。 - 通过给
sendBroadcast()
、sendOrderedBroadcast()
或sendStickyBroadcast()
之类的方法传入一个Intent
,你可以初始化一条广播消息。 - 通过调用
ContentResolver
的query()
方法,你可以在 Content Provider 上执行一条查询。
关于 Intent 的更多信息,请参阅文档Intents 和 Intent 过滤器。关于激活组件的更多信息,在以下文档中也有涉及:Activity、服务、BroadcastReceiver
和Content Provider。
Manifest 文件
在启动一个应用程序组件之前,Android 系统必须知道组件的存在,这是通过读取应用程序的 AndroidManifest.xml
文件(“Manifest”文件)来实现的。该文件必须位于项目的根目录,应用程序必须在该文件中声明所有的组件。
除了声明应用程序组件之外,Manifest 文件还有其他一些用途,比如:
- 确定应用程序所需的用户权限,如访问 Internet 或 读写用户通讯录
- 声明应用程序需要的最小版本API Level,表明应用程序将使用此版本的 API。
- 声明应用程序的的硬件和软件需求,诸如:摄像头、蓝牙服务和多点触屏。
- 应用程序需要链接的 API 库(Android 系统 API 之外的库),如:Google Maps library。
- 其他
声明组件
Manifest 文件的主要用途是把应用程序的组件告知系统。例如:Manifest 文件可以声明一个 Activity 如下:
<?xml version="1.0" encoding="utf-8"?><manifest ... > <application android:icon="@drawable/app_icon.png" ... > <activity android:name="com.example.project.ExampleActivity" android:label="@string/example_label" ... > </activity> ... </application></manifest>
在 < application >
元素中,android:icon
属性指向了一个标识该应用程序的图标资源,。
在 < activity >
元素中, android:name
属性设定了 Activity
子类的完全限定类名, android:label
属性设定了一个用作 Activity 标题的字符串。
必须按照以下规则声明应用程序的全部组件:
- 用于 Activity 的
< activity >
元素 - 用于服务的
< service >
元素 - 用于广播接收器的
< receiver >
元素 - 用于 Content Provider 的
< provider >
元素
如果你的代码中用到了某些 Activity、服务和 Content Provider,但没有在 Manifest 文件中声明,那么系统是看不见这些组件的,因此它们也就无法生效。 不过,广播接收器既可以在 Manifest 文件中进行声明,也可以用代码动态创建( 创建为 BroadcastReceiver
对象)并用 registerReceiver()
进行注册。
关于构建 Manifest 文件的更多信息,请参阅文档 AndroidManifest.xml 文件
声明组件的兼容性
正如 激活组件 部分所述,你可以用一个 Intent
来启动Activity、服务和广播接收器。你可以在 Intent 中使用显式命名的目标组件(用组件的类名)启动。 不过,Intent 真正的强大之处在于 隐式 Intent 的理念。 隐式 Intent 只要说明需执行的 Action 类型即可(还可附带 Action 用到的数据),系统可籍此在设备上查找可执行此 Action 的组件并启之。 如果同时存在多个组件都可以执行此 Action,则可以由用户选用一个。
通过将接收到的 Intent 和其他应用程序的 Manifest 文件给出中的 Intent 过滤器 进行比较,系统识别出可以响应 Intent 的组件。
当在应用程序的 Manifest 文件中声明 Activity 时,你还可以包含 Intent 过滤器,用于声明该 Activity 可以响应来自其他应用程序的 Intent。 通过在组件声明元素下添加一个子元素 < intent-filter >
,可以为该组件声明一个 Intent 过滤器。
例如,如果你已经建立了一个 Email 应用程序,其中带有一个撰写新邮件的 Activity, 你就可以声明一个响应”send“ 类型 Intent(用于发送新邮件)的 Intent 过滤器如下:
<manifest ... > ... <application ... > <activity android:name="com.example.project.ComposeEmailActivity"> <intent-filter> <action android:name="android.intent.action.SEND" /> <data android:type="*/*" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application></manifest>
然后,如果其他应用程序创建了一个 ACTION_SEND
类型的 Action,并传给 startActivity()
, 系统就可以启动你的Activity,用户就可以起草并发送一封 Email 了。
关于创建 Intent 过滤器的更多信息,请参阅文档 Intent 和 Intent 过滤器。
声明应用程序需求
Android 支持多种设备,这些设备并不是全都提供相同的硬件配置。 为了防止在不提供相应硬件的设备上安装你的应用程序,清晰地定义一个配置文件相当重要,这在 Manifest 文件中声明软硬件需求即可实现。 绝大部分声明仅仅是报告性质的,系统不会去读取它们。 但为了能让用户在搜索应用程序时按照硬件设备进行过滤,类似 Google Play 之类的外部服务将会读取这些信息。
例如,如果你的应用程序需要用到摄像头和 Android 2.1 以上的 API( API Level 7), 你就在 Manifest 文件中进行如下声明:
<manifest ... > <uses-feature android:name="android.hardware.camera.any" android:required="true" /> <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" /> ...</manifest>
现在,不提供摄像头的设备和低于2.1版本的 Android 就无法通过 Google Play 安装你的应用程序了。 Now, devices that do not have a camera and have an
不过,你还可以声明应用程序要使用摄像头但不是必需使用。 这时,你的应用程序必须将 required
设为 "false"
,并且在运行时检测是否存在摄像头,以便适时禁用与之有关的功能。
关于如何让应用程序保持与各种设备的兼容性,文档 设备兼容性 中给出了更为详细的信息。
应用程序资源
Android 应用程序并不仅仅由源代码构成 — 还需要用到资源文件,如图片、音频文件和其他所有的可视化内容,这些都是与源代码相分离的。 例如,你需要用 XML 文件定义动画、菜单、颜色、Activity 用户界面的 Layout。 资源文件使你不用修改源代码就可以方便地更换应用程序的外表 — 通过给出替代资源集 — ,你可以根据各种设备配置(比如不同的语言和屏幕尺寸)来优化应用程序。
SDK 编译工具会为 Android 项目中的每个资源都定义一个唯一的整数型 ID,以便从源代码或 XML 格式的其他资源中引用该资源。 例如,假设应用程序中包含一个名为 logo.png
的图片文件(保存在 res/drawable/
目录中), SDK 编译工具将会创建一个名为 R.drawable.logo
的唯一ID,你可以用此 ID 来引用该图片并把它放到用户界面中去。
要将资源文件从源代码中分离出来,要点之一是为各种设备配置给出不同的替代资源。 例如,通过定义 XML 格式的用于用户界面的字符串,你可以把字符串翻译为其他语言并保存到单独的文件中。 然后,根据资源目录名后面跟随的语言标识符(如法语字符串就是 res/values-fr/
),以及用户的语言设置, Android 系统将会把相应语言的字符串应用到用户界面中。
Android 对替代资源提供多种不同的 标识符。 为了定义某资源所需的设备配置,标识符即为该资源目录名中的短字符串。 再举个例子,根据设备的屏幕方向和尺寸,通常需要为 Activity 创建多种不同的 Layout。 比如,当设备屏幕是纵向放置时(高度较大),也许需要让按钮纵向布局。 而当屏幕横向放置时(宽度较大),按钮就应该横向对齐了。 要能根据屏幕方向来改变布局,你可以定义两个 Layout,并用合适的标识符为 Layout 目录命名。 这样,系统就能根据当前设备方向自动选用合适的 Layout。
关于应用程序可用的各种资源,以及如何为各种设备配置创建替代资源,更多信息请参阅 提供资源。
后续阅读:
- Intent 和 Intent 过滤器
- 有关用
Intent
API 激活诸如 Activity 和服务之类的应用程序组件、让组件可被其他应用程序使用等内容。 - Activity
- 有关创建
Activity
类的实例等内容。Activity 在应用程序中给出某个包含用户界面的窗口。 - 提供资源
- 有关资源和源代码分离的 Android 应用程序架构,包括为某种设备配置提供替代资源等内容。
还可能感兴趣:
- 设备兼容性
- 有关在各种型号设备上运行 Android 的信息,以及为每种设备优化程序或者限制功能。
- 系统权限
- Android 通过一套授权系统对应用程序访问某些 API 进行的限制,用户由此授权系统同意应用程序使用这些 API。
Android开发-API指南-应用程序开发基础