应用基础知识

您可以使用 Kotlin、Java 编程语言和 C++ 语言编写 Android 应用。Android SDK 工具会将您的代码以及任何数据和资源文件编译成 APK 或 Android App Bundle。

Android 软件包是一种带有 .apk 后缀的归档文件,其中包含运行时所需的 Android 应用的内容,也是 Android 设备用来安装应用的文件。

Android App Bundle 是一种后缀为 .aab 的归档文件,其中包含 Android 应用项目的内容,包括运行时不需要的一些其他元数据。AAB 是一种发布格式,无法在 Android 设备上安装。这会将 APK 生成和签名推迟到以后的阶段。

例如,通过 Google Play 分发您的应用时,Google Play 的服务器会生成经过优化的 APK,其中仅包含请求安装应用的特定设备所需的资源和代码。

每个 Android 应用都处于各自的安全沙盒中,并受到以下 Android 安全功能的保护:

  • Android 操作系统是一种多用户 Linux 系统,其中的每个应用都是一个不同的用户。
  • 默认情况下,系统会为每个应用分配一个唯一的 Linux 用户 ID,该 ID 仅供系统使用,应用不知道。系统会为应用中的所有文件设置权限,以便只有分配给该应用的用户 ID 才能访问这些文件。
  • 每个进程都有自己的虚拟机 (VM),因此一个应用的代码与其他应用是隔离开来的。
  • 默认情况下,每个应用都在自己的 Linux 进程中运行。Android 系统会在需要执行应用的任何组件时启动该进程,然后在不再需要该进程或系统必须为其他应用恢复内存时关闭该进程。

Android 系统实现了最小权限原则。也就是说,默认情况下,每个应用都只能访问执行其工作所需的组件,而不能访问其他组件。这样会创建一个非常安全的环境,在该环境中,应用无法访问系统其未获得权限的部分。

不过,应用可以通过一些方式与其他应用共享数据,以及访问系统服务:

  • 可以安排两个应用共享同一个 Linux 用户 ID,在这种情况下,它们可以访问彼此的文件。为了节省系统资源,您还可以安排具有相同用户 ID 的应用在同一 Linux 进程中运行并共享同一虚拟机。这些应用还必须使用相同的证书进行签名。
  • 应用可以请求访问设备数据(如设备的位置信息、相机和蓝牙连接)的权限。用户必须明确授予这些权限。如需详细了解权限,请参阅 Android 中的权限

本文档的其余部分将介绍以下概念:

  • 用于定义应用的核心框架组件
  • 您在其中声明组件和应用所需设备功能的清单文件。
  • 与应用代码分开且能让应用针对各种设备配置适当优化其行为的资源。

应用组件

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

应用组件有以下四种类型:

  • Activity
  • 服务
  • 广播接收器
  • Content provider

每种类型都有不同的用途,并且具有用于定义组件创建和销毁方式的不同生命周期。以下部分将介绍应用组件的四种类型。

activity
activity 是与用户交互的入口点。它表示具有界面的单个屏幕。例如,电子邮件应用可能具有一个显示新电子邮件列表的 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 参考文档。

广播接收器
广播接收器是一种组件,可让系统在常规用户流之外向应用传递事件,以便应用能够响应系统级广播通知。由于广播接收器是应用中的另一个明确定义的条目,因此系统甚至可以将广播传送到当前未运行的应用。

例如,应用可以安排闹钟来发布通知,告知用户即将进行的活动。由于闹钟是传递给应用中的 BroadcastReceiver,因此在闹钟响起之前,应用无需继续运行。

很多广播都源自系统,例如通知屏幕已关闭、电池电量不足或已拍摄照片的广播。应用还可以发起广播,例如告知其他应用某些数据已下载到设备上并可供其使用。

虽然广播接收器不会显示界面,但它们可以创建状态栏通知,以便在广播事件发生时提醒用户。但广播接收器更常见的用途只是作为通向其他组件的通道,旨在执行极少量的工作。

例如,广播接收器可能会使用 JobScheduler 根据事件安排 JobService 来执行一些工作。广播接收器常常涉及应用之间相互交互,因此在设置广播接收器时,请务必注意安全隐患。

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

content provider
content provider 管理一组共享的应用数据,您可以将这些数据存储在文件系统、SQLite 数据库、Web 或应用可以访问的任何其他永久性存储位置。如果 content provider 允许,其他应用可以通过 content provider 查询或修改数据。

例如,Android 系统提供用于管理用户联系信息的 content provider。任何具有适当权限的应用都可以查询 content provider(例如使用 ContactsContract.Data),以读取和写入有关特定人员的信息。

人们很容易将 content provider 视为数据库上的抽象,因为其中内置了许多 API 和支持来应对这种常见情况。不过,从系统设计的角度来看,它们的核心用途不同。

在系统中,content provider 是应用的入口点,用于发布由 URI 架构标识的已命名数据项。因此,应用可以决定如何将其包含的数据映射到 URI 命名空间,从而将这些 URI 分发给其他实体,而其他实体反过来又可以使用它们来访问数据。这可让系统在管理应用时执行以下特殊操作:

  • 分配 URI 不需要应用保持运行状态,因此 URI 在其所属应用退出后可以保留。系统只需确保拥有的应用在从相应的 URI 检索应用数据时仍在运行即可。
  • 这些 URI 还提供重要的精细安全模型。例如,应用可将其所拥有的图像的 URI 放到剪贴板,但将其 content provider 保持锁定状态,以便其他应用无法自由访问该图像。当第二个应用尝试访问剪贴板上的该 URI 时,系统可以允许该应用使用临时的 URI 权限授予访问数据,这样它就仅访问该 URI 后方的数据,而不访问第二个应用中的任何其他数据。

content provider 也适用于读取和写入您的应用不共享的私有数据。

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

Android 系统设计的独特之处在于,任何应用都可以启动其他应用的组件。例如,如果您希望用户使用设备的相机拍摄照片,可能有另一个应用可以执行此操作,而您的应用可以使用该应用,而无需开发 activity 自行拍摄照片。您无需整合甚至链接到相机应用中的代码,而是可以在相机应用中启动拍摄照片的 activity。完成后,系统甚至会将照片返回给您的应用,以便您使用。对用户而言,就好像相机是您应用的一部分。

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

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

激活组件

一种称为 intent 的异步消息会激活以下四种组件类型中的三种:activity、服务和广播接收器。intent 会在运行时将各个组件相互绑定。您可以将它们视为从其他组件请求操作的信使,无论该组件属于您的应用还是其他组件。

使用 Intent 对象创建 intent,该对象定义了一条消息来激活特定组件(显式 intent)或特定类型的组件(隐式 intent)。

对于 activity 和服务,intent 会定义要执行的操作(例如查看或发送某项内容),并可能会指定要执行操作的数据的 URI,以及正在启动的组件可能需要了解的其他信息。

例如,intent 可能传达对 activity 显示图片或打开网页的请求。在某些情况下,您可以启动一个 activity 来接收结果,在这种情况下,该 activity 也会在 Intent 中返回结果。您还可以发出 intent,让用户选择个人联系人并将其返回给您。返回 intent 包含指向所选联系人的 URI。

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

与 activity、服务和广播接收器不同,当来自 ContentResolver 的请求定位时,content provider 会被激活。内容解析器通过 content provider 处理所有直接事务,而组件通过提供程序执行事务会调用 ContentResolver 对象上的方法。出于安全原因,这会在 content provider 和请求信息的组件之间留出一个抽象层。

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

  • 您可以通过将 Intent 传递给 startActivity() 或当您希望 activity 返回结果时,为 startActivityForResult() 启动一个 activity 或为其指定新任务。
  • 在 Android 5.0(API 级别 21)及更高版本中,您可以使用 JobScheduler 类调度操作。对于较低的 Android 版本,您可以通过将 Intent 传递给 startService() 来启动服务或为持续性服务提供新指令。您可以通过将 Intent 传递给 bindService() 来绑定到该服务。
  • 您可以通过将 Intent 传递给 sendBroadcast()sendOrderedBroadcast() 等方法来发起广播。
  • 您可以通过对 ContentResolver 调用 query() 来对 content provider 执行查询。

如需详细了解如何使用 intent,请参阅 intent 和 intent 过滤器文档。以下文档详细介绍了如何激活特定组件:activity 简介服务概览BroadcastReceiver内容提供程序

清单文件

系统必须先读取应用的清单文件 AndroidManifest.xml,确认组件存在,然后 Android 系统才能启动应用组件。您的应用会在此文件(位于应用项目目录的根目录下)中声明其所有组件。

除了声明应用的组件之外,清单还会执行一些其他操作,例如:

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

声明组件

清单的主要任务是告知系统有关应用组件的信息。例如,清单文件可以按如下方式声明 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、服务和 content provider 对系统不可见,因此它们永远也不会运行。不过,广播接收器可以在清单中声明,也可以在代码中动态创建为 BroadcastReceiver 对象,并通过调用 registerReceiver() 在系统中注册。

如需详细了解如何为应用构建清单文件,请参阅应用清单概览

声明组件功能

激活组件部分所述,您可以使用 Intent 启动 activity、服务和广播接收器。为此,您可以在 intent 中使用组件类名明确命名目标组件。您还可以使用隐式 intent,该 intent 描述要执行的操作的类型,以及(可选)要对其执行操作的数据。隐式 intent 使系统能够在设备上找到可执行操作的组件并启动它。如果有多个组件可以执行 intent 所描述的操作,用户可选择使用哪一个。

注意:如果您使用 intent 启动 Service,请使用显式 intent 来确保应用是安全的。使用隐式 intent 启动服务存在安全隐患,因为您无法确定哪些服务会响应该 intent,而用户无法看到哪项服务已启动。从 Android 5.0(API 级别 21)开始,如果使用隐式 intent 调用 bindService(),系统会抛出异常。请勿为您的服务声明 intent 过滤器。

通过将收到的 intent 与设备上其他应用的清单文件中提供的 intent 过滤器进行比较,系统可以确定可以响应 intent 的组件。

在应用的清单中声明 activity 时,可以选择性地添加 intent 过滤器来声明 activity 的功能,以便它能够响应来自其他应用的 intent。为此,您需要将 <intent-filter> 元素添加为组件声明元素的子元素。

例如,如果您构建的电子邮件应用包含用于撰写新电子邮件的 activity,则可以声明一个 intent 过滤器,以响应“send” 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 操作的 intent,并将其传递给 startActivity(),系统可能会启动您的 activity,以便用户能够草拟和发送电子邮件。

如需详细了解如何创建 intent 过滤器,请参阅 intent 和 intent 过滤器文档。

声明应用要求

Android 设备多种多样,但并非所有设备都提供相同的特性和功能。为了防止您的应用安装在缺少应用所需功能的设备上,请务必在清单文件中声明设备和软件要求,为您的应用支持的设备类型明确定义一个配置文件。

大部分声明仅供参考。系统不会读取这些消息,但 Google Play 等外部服务会读取它们,以便在用户通过其设备搜索应用时为其提供过滤功能。

例如,假设您的应用需要相机,并使用 Android 8.0(API 级别 26)中引入的 API。您必须声明这些要求。 minSdkVersiontargetSdkVersion 的值是在应用模块的 build.gradle 文件中设置的:

android {
  ...
  defaultConfig {
    ...
    minSdkVersion 26
    targetSdkVersion 29
  }
}

注意:请勿直接在清单文件中设置 minSdkVersiontargetSdkVersion,因为它们在构建流程中会被 Gradle 覆盖。如需了解详情,请参阅指定 API 级别要求

您可以在应用的清单文件中声明相机功能:

<manifest ... >
    <uses-feature android:name="android.hardware.camera.any"
                  android:required="true" />
    ...
</manifest>

根据这些示例中显示的声明,没有相机或 Android 版本低于 8.0 的设备将无法从 Google Play 安装您的应用。不过,您也可以声明您的应用使用相机,但并不强制要求使用相机。为此,请将 required 属性设置为 false,在运行时检查设备是否具有相机,并根据需要停用任何相机功能。

如需详细了解如何管理应用与不同设备的兼容性,请参阅设备兼容性概览

应用资源

Android 应用不仅仅由代码组成。它需要与源代码分离的资源,例如图片、音频文件以及与应用的视觉呈现有关的任何内容。例如,您可以使用 XML 文件定义 activity 界面的动画、菜单、样式、颜色和布局。

借助应用资源,您无需修改代码即可轻松更新应用的各种特性。通过提供一组备用资源,您可以针对各种设备配置(例如不同的语言和屏幕尺寸)优化应用。

对于您在 Android 项目中添加的每项资源,SDK 构建工具都会定义一个唯一的整数 ID,您可以利用该 ID 来引用应用代码或 XML 中定义的其他资源中的资源。例如,如果您的应用包含名为 logo.png 的图片文件(保存在 res/drawable/ 目录中),则 SDK 工具会生成名为 R.drawable.logo 的资源 ID。此 ID 映射到一个应用特定的整数,您可以使用它来引用图片并将其插入界面中。

提供独立于源代码的资源,其中一个最重要的方面是能够为不同的设备配置提供备用资源。

例如,通过使用 XML 定义界面字符串,您可以将字符串翻译成其他语言,并将这些字符串保存在单独的文件中。然后,Android 会根据您附加到资源目录名称的语言限定符将适当的语言字符串应用到界面,例如 res/values-fr/ 表示法语字符串值,以及用户的语言设置。

Android 支持许多备用资源的限定符。限定符是包含在资源目录名称中的简短字符串,用于定义这些资源使用的设备配置。

例如,您可以根据设备的屏幕方向和尺寸为 activity 创建不同的布局。当设备屏幕为纵向(高)方向时,您可能需要一个按钮垂直排列的布局;但当屏幕处于横向(宽)方向时,您可能需要按钮水平对齐。如需根据屏幕方向更改布局,您可以定义两个布局,并为每个布局的目录名称应用适当的限定符。然后,系统会根据当前的设备屏幕方向自动应用适当的布局。

如需详细了解可在应用中添加的不同类型的资源,以及如何为不同的设备配置创建备用资源,请参阅应用资源概览。如需详细了解最佳实践,以及如何设计稳健且达到生产质量的应用,请参阅应用架构指南

其他资源

如需使用视频和代码教程学习 Android 开发,请参阅使用 Kotlin 开发 Android 应用 Udacity 课程。

继续阅读以下内容:

intent 和 intent 过滤器
了解如何使用 Intent API 激活应用组件(如 activity 和服务),以及如何让您的应用组件可供其他应用使用。
activity 简介
了解如何创建 Activity 类的实例,该实例可在应用中提供具有界面的独特屏幕。
应用资源概览
了解如何构建 Android 应用来将应用资源与应用代码分离,包括如何针对特定设备配置提供备用资源。

其他您可能感兴趣的内容:

设备兼容性概览
了解 Android 如何在不同类型的设备上发挥作用,以及如何针对每种设备优化您的应用,或如何限制您的应用在不同设备上的可用性。
Android 中的权限
了解 Android 如何通过权限系统来限制应用对特定 API 的访问权限,该系统要求征得用户同意,才允许您的应用使用这些 API。