|
组件是一个Android程序至关重要的构建模块。每一个组件都是系统进入你的应用的不同途径。但并不是所有的组件都是用户进入程序的真实入口,其中一些要依赖于其它组件, 但是每一个组件都以自己独有的形式存在,并发挥特殊的作用;每一个组件都是一个唯一的模块,帮助你实现程序的各种行为。 有四种不同的应用程序组件。每一种组件都有其唯一的目的并且有独有的生命周期,这个生命周期定义了附件被创建和销毁的方式。 下面介绍四种类型的应用程序组件: Activity一个 activity 为一个用户交互提供一个单独的界面。例如,一个邮件程序可能有一个activity,它展现了一个新邮件的列表。 另一个activity用来编辑邮件,还有一个是用来阅读邮件。 虽然这些activity组合在一起构成一个紧密的用户体验,但每一个都是相对独立的。 同样,其它程序也可以启动这些activity(如果这个邮件程序允许)。 例如,一个相机程序可以启动这个邮件程序的编辑邮件activity,如果用户想分享一张照片。Service一个 service是一个运行在后台的组件。它用于执行耗时操作或者远程进程。 一个service并不提供用户交互界面。例如,当用户在使用另外一个程序的时候,一个服务可能在播放音乐或者在 通过网络获取数据,这样不会阻塞住用户与activity的交互。其它的组件,例如一个activity,可以启动一个service并让其运行或者与其绑定,绑定后可以与其交互。Content provider一个content provider负责管理应用程序的数据共享集。 你可以通过文件系、SQLite数据库、网站,或者其它的你的应用程序可以访问的持久化存储位置来存储数据。 通过content provider,其它的应用程序可以查询甚至修改你的数据(如果这个content provider允许它们这么做)。 例如,Android系统提供了一个content provider来管理联系人信息。 同样地,任何程序拥有了适当权限都可以查询这个content provider (例如ContactsContract.Data) 去读写某人的信息。Content provider在读写程序的私有数据时也很有用。例如, Note Pad 范例程序就使用了一个content provider来保存笔记。 Broadcast receiverbroadcast receiver 是一个用来响应系统范围内的广播的组件。 很多广播发自于系统本身。—例如, 通知屏幕已经被关闭、电池低电量、照片被拍下的广播。 应用程序也可以发起广播。—例如, 通知其它程序,一些数据被下载到了设备,且可供它们使用。 虽然广播并不提供用户交互界面,它们也可以创建一个状态栏通知 来提醒用户一个广播事件发生了。尽管如此,更多的情形是,一个广播只是进入其它组件的一个“门路”,并试图做一些少量的工作。 例如,它可能发起一个服务,并通过服务执行与这个广播事件相关的工作。
Android系统设计的一个独特方面是,任何程序都可以启动其它程序的组件。 例如,如果你想让用户使用设备相机捕捉一个相片,有另外一个程序做这件事,那么你的程序将可以调用它, 而不是你自己开发一个拍照的activity。你不必从相机程序中嵌入代码或者连链接代码也不需要。取而代之地,你可以简单地启动相机程序中拍照的activity。 当拍照完成,相片就会返回给你的程序供你使用。从用户的角度,就好像相机就是你程序的一部分。 当系统启动一个组件,它其实就启动了这个程序的进程(如果这个进程还未被启动的话)并实例化这个组件所需要的类。 例如,如果你的程序启动了相机程序里的activity去拍照,这个activity实际上是运行在相机程序的进程里,而不是你自己的进程。 因此,不像其它系统里的程序,Android程序并不是单入口的(例如它没有main方法)。 由于系统把程序运行在一个个独立的进程中,并使用文件权限来限制对其它程序的访问,所以你的程序不能从其它程序中直接激活组件。 尽管如此,Android系统可以做到!激活一个其它程序的组件,你必须向系统发送一个信息,这个信息需要指定你的intent 来启动一个指定的组件。 然后系统就会为你激活这个组件。
激活组件四分之三的组件类型—activitie, service, 和 broadcast receiver—是被一个叫做 intent的异步消息激活的。 Intent把不同的独立的组件在运行期绑定在一起(你可以把它们当作从其它组件中请求动作的消息), 无论这些组件属于你的或者其它的程序。 一个intent使用一个 Intent 对象来创建, 它用于激活一个指定的或者指定 类型的组件。— 一个intent可以分别是显示的或者隐式的。 对于activity和service来说,一个intent定义了将要执行的动作。(例如, 查看或发送什么)并且可以指定动作执行需要的数据URL(启动组件所需要知道的其它数据)。 例如,一个intent可能发送一个请求,让一个activity去显示一张图片或打开一个网页。 某些情况下,你可以启动一个activity来接收一个结果,此时,这个activity也通过一个 Intent来返回结果。 (例如, 你可以发送一个intent让用户获取一个个人联系人,并让这个结果返回给你—返回的intent就包含了一个指向你选择的联系人的URI)。 对broadcast receiver来说, intent只是简单地定义了需要广播的公告(例如,一个指明设备电池电量低的广播就只包含了一个已知的动作字符串:“电量低”)。 另外一个组件类型, content provider, 不是用intent来激活。 相对地,它是由一个 ContentResolver 发起的一个指向它的请求激活的。 这个content resolver掌握了所有content provider的直接事务,所以用这个provider来执行事务的组件不需要直接执行而是调用这个 ContentResolver 对象的方法。 它在content provider和这个组件请求信息之间放置了一个抽象层(为了安全)。 激活各种类型组件有不同的方法:
配置文件
在Android系统能够启动一个程序组件之前, 系统必须通过读取程序的AndroidManifest.xml 文件 ("配置"文件)来知道这个组件是否存在。 你的程序必须在这个文件中声明它所有的组件。这文件必须放在程序项目的根目录中。 除了声明程序组件外,这个配置文件还做一些其它的工作,例如: - 确定程序需要哪些用户权限,例如网络访问或者读取用户的联系人。
- 声明程序需要的最小的 API Level 这个要参照程序都使用了哪些API。
- 声明程序使用或要求的硬件和软件特性,例如相机,蓝牙服务,或者多点触屏。
- 程序需要链接的API类库(除Android framework API之外的类库),例如 Google Map类库。
- 其它
声明组件配置文件的主要任务是通知系统,该应用程序都使用了哪些组件。 例如,一个配置文件可以这样声明一个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>
复制代码在 <activity> 元素中, android:name 属性指定了 Activity 子类的完整正确类名, 而 android:label 属性 指定了一个用于显示activity的用户可见标签的字符串。 你必须像这样声明所有的组件: 你包含在你程序中但并没有在配置文件中声明的Activitie, service, 和 content provider 是不被系统识别的,因此,也无法运行。但是, broadcast receiver既可以在配置文件中声明,也可以在代码中被动态创建(作为 BroadcastReceiver 对象) 并且通过调用 registerReceiver() 注册于系统中。 声明组件的用途如前文 激活组件的讨论中所说, 你可以使用一个 Intent 来启动一个activitie, service, 和 broadcast receiver。你可以明确地(使用组件的类名)在intent中声明一个目标组件。 但是, intent最牛逼的地方其实是它的动作(action)概念, 使用action,你可以简单地描述以下你想执行的动作(并且你也可以指定你想把哪些数据放在这个动作上) 并且允许系统去寻找设备上可以执行这个动作的组件并启动它。如果有多个组件可以执行这个动作,那么由用户来决定哪个去执行。 系统识别能够响应intent的组件的方法是比较收到的intent和设备的其它程序的配置文件中的intent filters 你在程序的配置文件中声明组件的时候,你就可以选择性地包含intent过滤器来声明组件的功能,这样它就能响应由其它程序发起的intent。 你可以通过添加一个 <intent-filter> 作为你组件的子元素 来为你的组件声明一个intent过滤器。 例如,一个包含编辑新邮件页面的邮件程序可能要在配置文件中声明一个intent过滤器,以此作为入口来响应“发送”intent(为了发送邮件)。 你程序中的一个Activity就要创建一个包含"发送"动作( ACTION_SEND) 的intent,这样系统在你通过 startActivity() 调用了这个intent时就去比较邮件程序的“发送”页面然后启动它。
声明程序的配置要求sAndroid设备多种多样,并不是所有的都提供了相同的特性和能力。 为了避免不满足你程序要求的设备去安装,你有必要清楚地在配置文件中声明设备和软件要求以定义哪些设备是你的程序支持的。 这些声明多数只是参考信息,系统并不去读取他们。但是额外的程序例如google play会为了筛选用户对应用程序的搜索。 例如,如果你的程序需要相机,并且使用了Andriod 2.1介绍的api ( API Level 7), 你就应该在配置文件中声明这些要求。这样的话, 没有相机且Android版本 低于2.1的就不能从Google Play中安装你的程序。 尽管如此,你也可以声明你的程序使用相机,但是不是硬性 要求 。这种情况下,你的程序必须在运行时执行一个校验,判断设备是否有相机功能,并且在没有相机的设备上禁用一切使用相机的特性。 下面有一些当你在设计和开发应用时需要考虑的设备特征: 设备尺寸和像素密度为了根据屏幕类型给设备分类,Android定义了两个设备特性:屏幕尺寸(屏幕的物理尺寸)和屏幕像素密度(屏幕像素的物理密度,或者叫dpi—每英寸的点数)。 为了简化屏幕配置的不同类型,Android系统把他们概括为可选择的分组,以便于他们容易被适配。屏幕尺寸包括: small, normal, large, 和 extra large.
屏幕像素密度包括: low density, medium density, high density, 和 extra high density. 默认地,你的应用程序可以适配所有尺寸和像素密度的屏幕,因为Android系统会对你的ui布局和图像资源做合适的调整。 尽管如此,你应该为特定的屏幕尺寸创建专门的布局,为特定的像素密度提供专门的图像资源。你要使用可选的布局资源,还要用 <supports-screens> 元素在配置文件中精确声明你的程序所支持的屏幕尺寸。 输入设置许多设备提供了不同的用户输入形式。例如硬键盘,轨迹球,或者一个五向导航板。如果你的程序需要一个特殊类型的输入硬件。 那么你需要在配置文件中使用<uses-configuration> 元素来声明。 尽管如此,很少由程序需要声明一个特定的输入配置。设备特性可能有很多硬件和软件特性并不一定都被一个已有的Android设备支持。例如相机,光感应器,蓝牙,一个特定版本的OpenGL,或者 一个精确的触摸屏。你可能永远不能断定某个特定的特性是被所有的Android设备支持的。(除非是是Android的标准类库), 所以你应该用<uses-feature>元素 来为你的程序使用到的特性加以声明。平台版本不同的Android设备经常运行了不同版本的Android平台,例如Android 1.6或者Android 2.3.每一个连续的版本 通常包含上个版本不支持的额外api。为了指明哪些api是可用的,么一个平台都指定了一个API Level。 (例如,Android 1.0是api 1,Android 2.3是api 9)。如果你使用了1.0版本以后加入的api,你应该声明这些API所在 的最小api level,需要使用<uses-sdk> 元素来声明。你为你的应用声明这些需求是很有必要的,因为当你在Google Play上发布应用时,它会根据这些声明来过滤出哪些应用时适用于这些设备的。 因此,你的程序也应该仅仅适用于满足于你程序的需求的设备。
|