应用组件

应用组件是 Android 应用的基本构建块。每个组件都是一个入口点,系统或用户可通过该入口点进入您的应用。有些组件会依赖于其他组件。

共有四种不同的应用组件类型:

  • Activity
  • 服务
  • 广播接收器
  • 内容提供程序

每种类型都有不同的用途和生命周期,后者会定义如何创建和销毁组件。以下部分将介绍应用组件的四种类型。

ActivityActivity 是与用户交互的入口点。它表示拥有界面的单个屏幕。例如,电子邮件应用可能有一个显示新电子邮件列表的 Activity、一个用于撰写电子邮件的 Activity 以及一个用于阅读电子邮件的 Activity。尽管这些 Activity 通过协作在电子邮件应用中形成一种紧密结合的用户体验,但每个 Activity 都独立于其他 Activity 而存在。因此,其他应用可以启动其中任何一个 Activity(如果电子邮件应用允许)。例如,相机应用可以启动电子邮件应用内用于撰写新电子邮件的 Activity,以便用户共享图片。Activity 有助于完成系统和应用程序之间的以下重要交互:

  • 追踪用户当前关心的内容(屏幕上显示的内容),以确保系统继续运行托管 Activity 的进程。
  • 了解先前使用的进程包含用户可能返回的内容(已停止的 Activity),从而更优先保留这些进程。
  • 帮助应用处理终止其进程的情况,以便用户可以返回已恢复其先前状态的 Activity。
  • 提供一种途径,让应用实现彼此之间的用户流,并让系统协调这些用户流。(此处最经典的示例是共享。)

您需将 Activity 作为 ​​Activity​​​ 类的子类来实现。如需了解有关 ​​Activity​​​ 类的更多信息,请参阅 ​​Activity​​ 开发者指南。

服务服务是一个通用入口点,用于因各种原因使应用在后台保持运行状态。它是一种在后台运行的组件,用于执行长时间运行的操作或为远程进程执行作业。服务不提供界面。例如,当用户使用其他应用时,服务可能会在后台播放音乐或通过网络获取数据,但这不会阻断用户与 Activity 的交互。诸如 Activity 等其他组件可以启动服务,使该服务运行或绑定到该服务,以便与其进行交互。事实上,有两种截然不同的语义服务可以告知系统如何管理应用:已启动服务会告知系统使其运行至工作完毕。此类工作可以是在后台同步一些数据,或者在用户离开应用后继续播放音乐。在后台同步数据或播放音乐也代表了两种不同类型的已启动服务,而这些服务可以修改系统处理它们的方式:

  • 音乐播放是用户可直接感知的服务,因此,应用会向用户发送通知,表明其希望成为前台,从而告诉系统此消息;在此情况下,系统明白它应尽全力维持该服务进程运行,因为进程消失会令用户感到不快。
  • 通常,用户不会意识到常规后台服务正处于运行状态,因此系统可以更自由地管理其进程。如果系统需要使用 RAM 来处理用户更迫切关注的内容,则其可能允许终止服务(然后在稍后的某个时刻重启服务)。

绑定服务之所以能运行,原因是某些其他应用(或系统)已表示希望使用该服务。从根本上讲,这是为另一个进程提供 API 的服务。因此,系统会知晓这些进程之间存在依赖关系,所以如果进程 A 绑定到进程 B 中的服务,系统便知道自己需使进程 B(及其服务)为进程 A 保持运行状态。此外,如果进程 A 是用户关心的内容,系统随即也知道将进程 B 视为用户关心的内容。由于存在灵活性(无论好坏),服务已成为非常有用的构建块,并且可实现各种高级系统概念。动态壁纸、通知侦听器、屏幕保护程序、输入方法、无障碍功能服务以及众多其他核心系统功能均可构建为在其运行时由应用实现、系统绑定的服务。

您需将服务作为 ​​Service​​​ 的子类来实现。如需了解有关 ​​Service​​​ 类的更多信息,请参阅​​服务​​开发者指南。

注意:如果您的应用面向 Android 5.0(API 级别 21)或更高版本,请使用 ​​JobScheduler​​​ 类来调度操作。JobScheduler 的优势在于,它能通过优化作业调度来降低功耗,以及使用 ​​Doze​​​ API,从而达到省电目的。如需了解有关使用此类的更多信息,请参阅 ​​JobScheduler​​ 参考文档。

广播接收器

借助广播接收器组件,系统能够在常规用户流之外向应用传递事件,从而允许应用响应系统范围内的广播通知。由于广播接收器是另一个明确定义的应用入口,因此系统甚至可以向当前未运行的应用传递广播。例如,应用可通过调度提醒来发布通知,以告知用户即将发生的事件。而且,通过将该提醒传递给应用的广播接收器,应用在提醒响起之前即无需继续运行。许多广播均由系统发起,例如,通知屏幕已关闭、电池电量不足或已拍摄照片的广播。应用也可发起广播,例如,通知其他应用某些数据已下载至设备,并且可供其使用。尽管广播接收器不会显示界面,但其可以​​创建状态栏通知​​,在发生广播事件时提醒用户。但广播接收器更常见的用途只是作为通向其他组件的通道,旨在执行极少量的工作。例如,它可能会根据带 ​​JobScheduler​​​ 的事件调度 ​​JobService​​ 来执行某项工作

广播接收器作为 ​​BroadcastReceiver​​​ 的子类实现,并且每条广播都作为 ​​Intent​​​ 对象进行传递。如需了解详细信息,请参阅 ​​BroadcastReceiver​​ 类。

内容提供程序内容提供程序管理一组共享的应用数据,您可以将这些数据存储在文件系统、SQLite 数据库、网络中或者您的应用可访问的任何其他持久化存储位置。其他应用可通过内容提供程序查询或修改数据(如果内容提供程序允许)。例如,Android 系统可提供管理用户联系人信息的内容提供程序。因此,任何拥有适当权限的应用均可查询内容提供程序(如 ​​ContactsContract.Data​​),以读取和写入特定人员的相关信息。我们很容易将内容提供程序看作数据库上的抽象,因为其内置的大量 API 和支持时常适用于这一情况。但从系统设计的角度看,二者的核心目的不同。对系统而言,内容提供程序是应用的入口点,用于发布由 URI 架构识别的已命名数据项。因此,应用可以决定如何将其包含的数据映射到 URI 命名空间,进而将这些 URI 分发给其他实体。反之,这些实体也可使用分发的 URI 来访问数据。在管理应用的过程中,系统可以执行以下特殊操作:

  • 分配 URI 无需应用保持运行状态,因此 URI 可在其所属的应用退出后继续保留。当系统必须从相应的 URI 检索应用数据时,系统只需确保所属应用仍处于运行状态。
  • 这些 URI 还会提供重要的细粒度安全模型。例如,应用可将其所拥有图像的 URI 放到剪贴板上,但将其内容提供程序锁定,以便其他应用程序无法随意访问它。当第二个应用尝试访问剪贴板上的 URI 时,系统可允许该应用通过临时的URI 授权来访问数据,这样便只能访问 URI 后面的数据,而非第二个应用中的其他任何内容。

内容提供程序也适用于读取和写入您的应用不共享的私有数据。

内容提供程序作为 ​​ContentProvider​​​ 的子类实现,并且其必须实现一组标准 API,以便其他应用能够执行事务。如需了解详细信息,请参阅​​内容提供程序​​开发者指南。

Android 系统设计的独特之处在于,任何应用都可启动其他应用的组件。例如,当您想让用户使用设备相机拍摄照片时,另一个应用可能也可执行该操作,因而您的应用便可使用该应用,而非自行产生一个 Activity 来拍摄照片。您无需加入甚至链接到该相机应用的代码。只需启动拍摄照片的相机应用中的 Activity 即可。完成拍摄时,系统甚至会将照片返回您的应用,以便您使用。对用户而言,这就如同相机是您应用的一部分。

当系统启动某个组件时,它会启动该应用的进程(如果尚未运行),并实例化该组件所需的类。例如,如果您的应用启动相机应用中拍摄照片的 Activity,则该 Activity 会在属于相机应用的进程(而非您的应用进程)中运行。因此,与大多数其他系统上的应用不同,Android 应用并没有单个入口点(即没有 ​​main()​​ 函数)。

由于系统在单独的进程中运行每个应用,且其文件权限会限制对其他应用的访问,因此您的应用无法直接启动其他应用中的组件,但 Android 系统可以。如要启动其他应用中的组件,请向系统传递一条消息,说明启动特定组件的 Intent。系统随后便会为您启动该组件。

启动组件

在四种组件类型中,有三种(Activity、服务和广播接收器)均通过异步消息 Intent 进行启动。Intent 会在运行时对各个组件进行互相绑定。您可以将 Intent 视为从其他组件(无论该组件是属于您的应用还是其他应用)请求操作的信使。

您需使用 ​​Intent​​ 对象创建 Intent,该对象通过定义消息来启动特定组件(显式 Intent)或特定的组件类型(隐式 Intent)。

对于 Activity 和服务,Intent 会定义要执行的操作(例如,查看发送某内容),并且可指定待操作数据的 URI,以及正在启动的组件可能需要了解的信息。例如,Intent 可能会传达对 Activity 的请求,以便显示图像或打开网页。在某些情况下,您可以通过启动 Activity 来接收结果,这样 Activity 还会返回 ​​Intent​​ 中的结果。例如,您可以发出一个 Intent,让用户选取某位联系人并将其返回给您。返回 Intent 包含指向所选联系人的 URI。

对于广播接收器,Intent 只会定义待广播的通知。例如,指示设备电池电量不足的广播只包含指示“电池电量不足”的已知操作字符串。

与 Activity、服务和广播接收器不同,内容提供程序并非由 Intent 启动。相反,它们会在成为 ​​ContentResolver​​​ 的请求目标时启动。内容解析程序会通过内容提供程序处理所有直接事务,因此通过提供程序执行事务的组件便无需执行事务,而是改为在 ​​ContentResolver​​ 对象上调用方法。这会在内容提供程序与请求信息的组件之间留出一个抽象层(以确保安全)。

每种组件都有不同的启动方法:

  • 如要启动 Activity,您可以向​​startActivity()​​​ 或​​startActivityForResult()​​​ 传递​​Intent​​(当您想让 Activity 返回结果时),或者为其安排新任务。
  • 在 Android 5.0(API 级别 21)及更高版本中,您可以使用​​JobScheduler​​​ 类来调度操作。对于早期 Android 版本,您可以通过向​​startService()​​​ 传递​​Intent​​​ 来启动服务(或对执行中的服务下达新指令)。您也可通过向将​​bindService()​​​ 传递​​Intent​​ 来绑定到该服务。
  • 您可以通过向​​sendBroadcast()​​​、​​sendOrderedBroadcast()​​​ 或​​sendStickyBroadcast()​​​ 等方法传递​​Intent​​ 来发起广播。
  • 您可以通过在​​ContentResolver​​​ 上调用​​query()​​,对内容提供程序执行查询。

如需了解有关 Intent 用法的详细信息,请参阅 ​​Intent 和 Intent 过滤器​​​文档。以下文档将为您详细介绍如何启动特定组件:​​Activity​​​、​​服务​​​、​​BroadcastReceiver​​ 和内容提供程序。

清单文件

在 Android 系统启动应用组件之前,系统必须通过读取应用的清单文件 (​​AndroidManifest.xml​​) 确认组件存在。您的应用必须在此文件中声明其所有组件,该文件必须位于应用项目目录的根目录中。

除了声明应用的组件外,清单文件还有许多其他作用,如:

  • 确定应用需要的任何用户权限,如互联网访问权限或对用户联系人的读取权限。
  • 根据应用使用的 API,声明应用所需的最低​​API 级别​​。
  • 声明应用使用或需要的硬件和软件功能,如相机、蓝牙服务或多点触摸屏幕。
  • 声明应用需要链接的 API 库(Android 框架 API 除外),如​​Google 地图库​​。

作者:​​靠谱杨​​​,​

更多日常分享尽在我的VX公众号:小杨的挨踢IT生活

Android官方文档_提供程序