[Android Core] Fundamentals 是基本原理的意思.

sddtc 于 2020-12-01 发布

概要

Android 应用可是使用 Kotlin, Java, C++ 这些语言来构建. Android SDK tools 会将你的代码和数据, 资源文件一起编译成 APK 包. 一个 APK 包文件包含了所有和应用相关的资源文件, 并可以安装在支持 Android 系统的设备上。
每一个 Android app 拥有属于它自己的安全沙盒, 主要的安全特性有以下几点:

Android 系统遵循的是最小权限原则(the principle of least privilege.). 也就是说, 默认情况下, 每个应用程序只能访问执行其工作所需的组件, 而不能访问其他组件. 这将创建一个非常安全的环境, 在该环境中, 应用程序无法访问未获得其权限的系统部分.
然而还是有一些方式可以在 app 间共享数据文件, 或者访问系统服务:

App 组件

应用程序组件是 Android app 的基本组成部分。 每个组件都是系统或用户可以通过其进入您的应用程序的入口点。 有些组件依赖于其他组件。Google 的文档将组件分为了 4 大类, 每种类型都有不同的用途,并且具有不同的生命周期,该生命周期定义了如何创建和销毁组件:

Activities

Activity 是和用户交互的入口。 它可以用一个单一的 app 屏幕来提供用户交互。 例如, 一个邮件 app 可以有一个 Activity 用来展示用户的新邮件列表,有一个 Activity 用来写邮件,再有一个 Activity 用来读取邮件。 尽管这些活动可以共同协作以在电子邮件 app 中形成极具凝聚力的用户体验,但是每个 Activity 都是彼此独立的。 例如,如果该邮件 app 支持其它 app 打开它,那么它可以选择打开这三种 Activity 的其中之一。 例如,一个拍照 app 可以允许用户分享照片:以邮件的内容的形式分享。 一个 Activity 促进了系统和 app 之间的以下关键交互:

Services

Service 是一个出于通用原因的入口,用于保持 app 在后台运行。 它以组件的形式在后台运行以执行需要长时间的操作,或为远程进程执行工作。 Service 不提供用户交互。 例如,当用户的手机打开其它 app 时, Service 可以仍然在后台为用户播放音乐, 或从远端请求数据。 另一个组件(例如 Activity)可以启动 Service,并使其运行或绑定到该 Service,以便与其进行交互。 实际上,有两个截然不同的语义 Services 告诉系统如何管理 app:启动的 Services 告诉系统使它们保持运行状态直到工作完成。 这可能是为了在后台同步某些数据,或者甚至在用户离开应用程序后播放音乐。在后台同步数据或播放音乐也代表两种不同类型的已启动 Services,这些服务会修改系统处理它们的方式:

绑定的那些服务之所以都在运行状态,是因为其他某个 app(或系统)已经表示要使用该服务。一般情况是 service 向另一个进程提 API 服务。因此系统知道这些进程之间存在依赖性。 如果进程 A 绑定进程 B 中的 Service,则它知道它需要使进程 B (及其 Service)保持为 A 运行。此外,如果进程 A 是某种用户关心的事,那么它也知道将进程 B 同样视为用户关心的事。 由于 Services 的这些灵活性(无论好坏),对于所有更高级别的系统概念而言,Service 已成为非常有用的构建块: 动态壁纸,通知监听器,屏幕保护程序,输入法,可访问性服务以及许多其他核心系统功能都是作为 app 实现的 Services 构建的,系统在应该运行他们的时候绑定这些服务。

Broadcast receivers

Broadcast receiver 是使系统能够将事件传递到 app 的组件,该事件不受用户 flow 的限制,从而使 app 能够响应系统范围的广播公告。 由于 Broadcast receiver 是 app 中另一个定义明确的入口,因此系统甚至可以将广播传送到当前未运行的应用程序。 例如,app 可以定义警报并以通知的形式发布,以通知用户即将发生的事件… 并通过将该警报传递给 app 的 Broadcast receiver,所以在 app 收到该报警前没有必要一直保持运行状态。
许多 Broadcast receiver 都来自系统本身。例如,通知屏幕即将关闭,电池电量不足或拍摄了图片。 app 还可以初始化广播,例如,让其他 app 知道某些数据已下载到设备上,可供他们使用。
尽管 Broadcast receiver 也没有用户交互界面,但它们可以在发生广播事件时通过创建状态栏通知来提醒用户。 然而更常见的是,Broadcast receiver 只是通向其他组件的 gateway - 旨在做很少的工作。 例如,它可以安排事件 JobService 来根据 JobScheduler 事件执行一些工作。

Content providers

Content provider 用于管理一系列的可共享的 app 数据。 你可以将其存储在文件系统,SQLite数据库,存储在 Web 端或 app 可访问到的任何其他持久性存储位置中。 通过 Content provider 其它 apps 可以查询/更新相关数据。 例如,Android 系统提供了一个 Content provider,用于管理用户的通讯录。 那么具有相关权限的任何 app 都可以通过 Content provider 查询通讯录数据,例如ContactsContract.Data,以读取和写入有关特定人员的信息。
将 Content provider 视为数据库的抽象是很聪明的想法,因为它通常内置了许多 API 和相关的支持。 然而从系统设计的角度来看它具有另一个重要的目的: 对于系统而言,Content provider 是 app 的入口点,用于发布由 URI 标识的数据项。 因此 app 可以决定如何将其包含的数据映射到 URI 命名空间,并将这些 URI 分发给其他实体,这些实体又可以使用它们来访问数据。这使系统可以在管理 app 中做一些特殊的事情:

Content provider 对于读取和写入关于你的 app 的私有未共享的数据同样也很有用。

Android 系统设计的一个独特方面你应该在上面的文章中了解到了, 它允许任何 app 都可以启动另一个 app 的组件。例如,如果您希望用户使用设备相机拍摄照片,则可能有另一个应用程序可以执行此操作,而您的 app 可以使用它来代替自己去开发一个 Activity 来用于拍摄照片。你无需侵入甚至链接到相机 app 中的代码中。你只需在捕获照片的相机 app 中启动 相应的 Activity 即可。完成后,拍摄好的照片会呈现在你的 app 中以便你使用。对于用户来说相机拍摄功能“似乎”实际上是你自己的 app 的一部分。

当系统启动一个组件时,如果该组件相关的代码还未实例化/未初始化/并不是运行状态,则会首先启动该 app 的进程,并实例化该组件所需的类。 例如,如果你的 app 在捕获照片的相机 app 中启动 Activity,则该 Activity 将在属于相机 app 的进程中运行,而不是在你的 app 的进程中运行。 因此与大多数其他系统上的 app 不同,Android app 没有单一的入口点(没有 main() 函数)。

由于每个 app 运行在系统中独立的每个进程里,并且文件权限限制了对其他 app 的访问,因此你的 app 无法直接从另一个 app 激活组件。 然而 Android 系统可以做到。 所以若要激活另一个 app 中的组件,请向系统发送一条消息,指定你启动特定组件的意图。 这样,系统会为你激活相应的组件。

Activating components

在上面介绍的四大组件中,有三个 (activities, services, and broadcast receivers) 的激活方式是通过 intent 这种异步消息来激活。 Intents 在运行时将各种独立的组件进行绑定。你可以将它们想象为请求其他组件执行操作的 messengers,无论该组件属于你的 app 还是其他 app。

Intent 对象创建一个 intent,该对象定义了一条消息以激活特定组件(explicit intent)或特定类型的组件(implicit intent).

对于 Activities 和 Services,intent 定义了要执行的动作(例如,查看/发送内容),并且可以指定要执行操作的数据的 URI,其中还可包括正在启动的组件可能需要了解的其他内容。例如,一个 intent 可能传递一个活动请求以显示图像或打开网页。在一些情况下,你可以启动 Activity 来接收结果,在该情况下,活动还会以 Intent 返回结果。例如,您可以发布 intent 让用户选择个人联系人并将其返回给你。返回 intent 包括指向所选联系人的 URI。

对于 broadcast receivers,此 intent 仅定义正在广播的公告。例如,指示设备电池电量低的广播仅包括指示电池电量低的已知操作字符串。

Activities, Services, and Broadcast receivers 不同, Content providers 不会被 intent 激活。它们被 ContentResolver 的请求作为目标时激活。 content resolver handlersContent providers 的所有直接交互,通过调用 ContentResolver 对象上的方法。这就在 Content providers 和请求信息的组件之间保留了一层抽象(出于安全性考虑)。

原文: Application Fundamentals