Android应用基础概念
简介
一、四种应用组件:
-
Activity
Activity 是与用户交互的入口点。它表示拥有界面的单个屏幕。
-
服务
服务是一个通用入口点,用于因各种原因使应用在后台保持运行状态。它是一种在后台运行的组件,用于执行长时间运行的操作或为远程进程执行作业。服务不提供界面。事实上,有两种截然不同的语义服务可以告知系统如何管理应用:已启动服务会告知系统使其运行至工作完毕。此类工作可以是在后台同步一些数据,或者在用户离开应用后继续播放音乐。在后台同步数据或播放音乐也代表了两种不同类型的已启动服务,而这些服务可以修改系统处理它们的方式:
- 音乐播放是用户可直接感知的服务,因此,应用会向用户发送通知,表明其希望成为前台,从而告诉系统此消息;在此情况下,系统明白它应尽全力维持该服务进程运行,因为进程消失会令用户感到不快。
- 通常,用户不会意识到常规后台服务正处于运行状态,因此系统可以更自由地管理其进程。如果系统需要使用 RAM 来处理用户更迫切关注的内容,则其可能允许终止服务(然后在稍后的某个时刻重启服务)。
绑定服务之所以能运行,原因是某些其他应用(或系统)已表示希望使用该服务。从根本上讲,这是为另一个进程提供 API 的服务。因此,系统会知晓这些进程之间存在依赖关系,所以如果进程 A 绑定到进程 B 中的服务,系统便知道自己需使进程 B(及其服务)为进程 A 保持运行状态。此外,如果进程 A 是用户关心的内容,系统随即也知道将进程 B 视为用户关心的内容。由于存在灵活性(无论好坏),服务已成为非常有用的构建块,并且可实现各种高级系统概念。动态壁纸、通知侦听器、屏幕保护程序、输入方法、无障碍功能服务以及众多其他核心系统功能均可构建为在其运行时由应用实现、系统绑定的服务。您需将服务作为
Service
的子类来实现。 -
广播接收器
借助广播接收器组件,系统能够在常规用户流之外向应用传递事件,从而允许应用响应系统范围内的广播通知。由于广播接收器是另一个明确定义的应用入口,因此系统甚至可以向当前未运行的应用传递广播。例如,应用可通过调度提醒来发布通知,以告知用户即将发生的事件。而且,通过将该提醒传递给应用的广播接收器,应用在提醒响起之前即无需继续运行。许多广播均由系统发起,例如,通知屏幕已关闭、电池电量不足或已拍摄照片的广播。应用也可发起广播,例如,通知其他应用某些数据已下载至设备,并且可供其使用。尽管广播接收器不会显示界面,但其可以创建状态栏通知,在发生广播事件时提醒用户。但广播接收器更常见的用途只是作为通向其他组件的通道,旨在执行极少量的工作。例如,它可能会根据带
JobScheduler
的事件调度JobService
来执行某项工作。广播接收器作为BroadcastReceiver
的子类实现,并且每条广播都作为Intent
对象进行传递。 -
内容提供程序
内容提供程序管理一组共享的应用数据,您可以将这些数据存储在文件系统、SQLite 数据库、网络中或者您的应用可访问的任何其他持久化存储位置。其他应用可通过内容提供程序查询或修改数据(如果内容提供程序允许)。内容提供程序也适用于读取和写入您的应用不共享的私有数据。
内容提供程序作为
ContentProvider
的子类实现,并且其必须实现一组标准 API,以便其他应用能够执行事务。
因此,与大多数其他系统上的应用不同,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()
,对内容提供程序执行查询。
三、清单文件
在 Android 系统启动应用组件之前,系统必须通过读取应用的清单文件 (AndroidManifest.xml
) 确认组件存在。您的应用必须在此文件中声明其所有组件,该文件必须位于应用项目目录的根目录中。
除了声明应用的组件外,清单文件还有许多其他作用,如:
- 确定应用需要的任何用户权限,如互联网访问权限或对用户联系人的读取权限。
- 根据应用使用的 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 的
<activity>
元素。 - 服务的
<service>
元素。 - 广播接收器的
<receiver>
元素。 - 内容提供程序的
<provider>
元素。
如果未在清单文件中声明源代码中包含的 Activity、服务和内容提供程序,则这些组件对系统不可见,因此也永远不会运行。不过,您可以 BroadcastReceiver
对象的形式,在清单中声明或在代码中动态创建广播接收器;以及通过调用 registerReceiver()
,在系统中注册广播接收器。
启动组件,使用Intent发出,通过将收到的 Intent 与设备上其他应用的清单文件中提供的 Intent 过滤器进行比较,系统便可识别能响应 Intent 的组件。
四、声明应用要求
您必须通过在清单文件中声明设备和软件要求,为该应用支持的设备类型明确定义一个配置文件。其中的大多数声明只是为了提供信息,系统并不会读取它们,但 Google Play 等外部服务会读取它们,以便在用户通过其设备搜索应用时为用户提供过滤功能。
<manifest ... >
<uses-feature android:name="android.hardware.camera.any" android:required="true" />
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" /> ...</manifest>
五、应用资源
对于您在 Android 项目中加入的每一项资源,SDK 构建工具均会定义唯一的整型 ID,您可以利用此 ID 来引用资源,这些资源或来自应用代码,或来自 XML 中定义的其他资源。例如,如果您的应用包含名为 logo.png
的图像文件(保存在 res/drawable/
目录中),则 SDK 工具会生成名为 R.drawable.logo
的资源 ID。此 ID 映射到应用特定的整型数,您可以利用它来引用该图像,并将其插入您的界面。
如果提供与源代码分离的资源,则其中最重要的一个优点在于,您可以提供适用于不同设备配置的备用资源。例如,通过在 XML 中定义界面字符串,您可以将字符串翻译为其他语言,并将这些字符串保存在单独的文件中。然后,Android 系统会根据向资源目录名称追加的语言限定符(如为法语字符串值追加 res/values-fr/
)和用户的语言设置,对您的界面应用相应的语言字符串。
Android 支持许多不同的备用资源限定符。限定符是资源目录名称中加入的短字符串,用于定义这些资源适用的设备配置。例如,您应根据设备的屏幕方向和尺寸为 Activity 创建不同的布局。当设备屏幕为纵向(长型)时,您可能想要一种垂直排列按钮的布局;但当屏幕为横向(宽型)时,可以按水平方向排列按钮。如要根据方向更改布局,您可以定义两种不同的布局,然后对每个布局的目录名称应用相应的限定符。然后,系统会根据当前设备方向自动应用相应的布局。