Android
应用程序是用Java
语言编写的。Android SDK
工具编译代码并将其连同数据和资源文件打包成APK
(Android Package
,一个以.apk
为后缀的档案文件)。APK
文件包含一个应用程序的所有内容,是使用Android
操作系统的设备安装应用程序的文件。
一旦应用程序被安装在设备上,它就“生活“在自己的安全沙盒里。
-
Android
操作系统是一个多用户的Linux
系统,每一个应用程序是系统的一个不同的用户。 -
Android
操作系统默认为每个应用程序分配一个唯一的Linux
用户ID
(这个ID
只有Android操作系统使用,其他应用程序不能获知)。Android
系统为应用程序的所有文件都设置了权限,只有具有该应用程序的用户ID
的用户可以访问。 - 每个进程有它自己的虚拟机,每个应用程序的代码彼此隔离运行。
- 每个应用程序默认都运行在自己的
Linux
进程中。当应用程序的任何一个组件需要执行时,Android
就会开启它的进程。而在当应用程序关闭或者系统要为其他应用回收内存时,就会关闭应用程序的进程。
Android
系统以这种方式实现了最少特权原则。也就是说,每个应用程序默认仅能它运行依赖的组件。这就创建了一个非常安全的环境,一个应用程序不能访问它没有权限访问的系统部分。
然而,也存在着应用程序和其他应用程序共享数据、应用程序获取系统服务的方式:
- 可以安排两个应用程序共享同一个
Linux
用户ID
。在这种情况下,它们可以访问彼此的文件。为了节省系统资源,具有同样的用户ID的应用程序也可以被安排运行在同一个Linux
进程中,共享同一个虚拟机(应用程序必须由同一个证书标记) - 应用程序根据需要可以请求获取服务数据,例如用户的联系人、短信、可插拔存储设备(
SD
卡)、相机、蓝牙等。所有应用程序权限都要由用户在安装时授权。
以上内容涵盖了一个Android应用程序如何存在系统中的基础内容。下面介绍:
- 定义应用程序的核心框架
- 为应用程序声明组件和需要的设备特性的清单文件
- 与应用程序代码分离的资源,支持应用程序为不同的设备配置优雅地优化自己的行为。
应用程序组件
应用程序组件是Android
应用程序的重要的构建块。每个组件都是系统启动应用程序的不同的入口点。并不是所有的组件都是用户实际启动应用程序的入口,有些是依赖于其他组件的。但是每一个组件都作为一个实体存在并且扮演着特定的角色-每一个组件都是帮助定义应用程序的整体行为的独一无二的构建块。
有四类不同的组件。每类组件具有不同的目的,并且具有不同的定义组件创建和消亡的生命周期。
以下是四类应用程序组件:
- 活动。活动代表具有用户界面的单幕。例如一个电子邮件应用程序可能有一个显示一列新邮件的活动,还有一个编辑邮件的活动和一个读邮件的活动。尽管在电子邮件应用程序中多个活动一起工作形成一个完整的用户体验,但活动间实际上是彼此独立的。因此,如果电子邮件应用程序允许,一个不同的应用程序可以启动它的任何一个活动。例如一个相机应用程序可以开启电子邮件应用程序的活动编写新的电子邮件以和其他用户分享图片。
- 服务。服务是一个在后台运行、执行需要长时间运行的操作或者远程进程的任务。服务并不提供用户界面。例如,当用户在一个不同的应用程序中时一个服务可能在后台播放音乐,又或者它正在不阻塞一个活动的用户界面地从网络上获取数据。其他组件(例如活动)可以启动服务,使它执行或者绑定到其上以和它交互。
- 内容提供者。内容提供者管理一组共享的应用程序数据集合。可以将数据存储在文件系统、
SQLite
数据库、网络或者其他应用程序可以访问的永久存储位置。如果内容提供者允许的话,其他应用程序可以通过内容提供者查询甚至修改这些数据。例如Android系统提供了一个管理用户的联系人信息的内容提供者。这样,任何一个具有适当权限的应用程序可以访问这个内容提供者的某部分数据(例如ContactsContract.Data)来读写关于某个人的信息。内容提供者对于写对自己应用程序来说私有、不共享的数据也很有帮助。 - 广播接收者。广播接受者是一个响应系统范围的广播公告的组件。很多广播来源于系统,例如通知屏幕关闭、电量低、已截获图片等广播。应用程序也可以发起广播,例如让其他应用程序知道某个数据已经被下载到设备上,它们可以使用了。尽管广播接收者并不显示用户界面,当广播事件发生时,它们可能创建一个状态栏通知来提醒用户。但是更普遍的是,广播接收者只是一个通往其他组件的大门,意在做非常少量的工作。
Android
系统设计的一个独一无二的方面是任何一个应用程序都可以启动其他应用程序的组件。例如你想要用户使用相机来拍摄一张照片,可能已经有另一个应用程序支持这个功能,那么就可以直接使用这个应用程序而不需要为你的应用程序再开发一个活动来获取照片。不需要合并或者链接到相机应用程序的代码,相反,你只是简单地启动相机应用程序的活动来获取一张照片。当拍摄完成后,这个照片甚至返回到你的应用程序,直接就可以使用了。对于用户来说,这个相机看起来好像是你的应用程序的一部分。
当系统启动一个组件时,它启动了这个应用程序的进程(如果它没有在运行的话)并且实例化这些组件需要的类。例如,如果你的应用程序启动了相机应用程序的一个活动来拍摄照片,那么这个活动运行在相机应用程序的进程中,而不是在你的应用程序的进程里。因此,不像其他大多数系统一样,Android
应用程序并不只有一个入口点(例如没有main
函数)。
因为系统在各自的进程中运行应用程序,不同的应用程序的文件具有访问权限,限制其他应用程序的访问。因此,不能直接从一个应用程序来启动另一个应用程序的组件。为了启动其他应用程序的组件,必须给系统传递一个消息指定你启动某一个特定组件的意图,然后由系统来启动这个组件。
启动组件
四类组件中的三个活动、服务和广播接收者由一个称作意图的异步消息启动。系统在运行过程中将组件彼此绑定(可以将意图想象成请求其他组件活动的使者),无论这些组件是否属于同一个应用程序。
意图通过Intent对象创建,定义了启动一个特定的组件或一类特定类型组件的消息,意图可以是显式的,也可以是隐式的。
对于活动和服务,意图定义了执行的活动(例如看或发送什么东西),而且可能指定了要处理的数据的URI(这是被启动的组件可能需要知道的东西之一)。例如一个意图可能是要请求一个活动显示一张图片或者打开一个网页。在某些情况下,可以启动一个活动并等待接收结果,在这种情况下,结果也是利用意图的形式返回的(例如,可以通过意图请求用户选择一联系人并将它返回,返回的意图中包括指向被选择的联系人的URI)。
对于广播接收者来说,意图简单地定义了被广播的通告(例如,一个表示设备电量低的广播只包括一个已知的表示电量低的动作字符串)。
另一个组件类型内容提供者并不由意图启动,而是当内容裁决器(ContentResolver
)请求时启动。内容裁决器处理所有与内容提供者直接的事务,这样使用内容提供者执行事务的组件不需要直接访问内容提供者,而是调用ContentResolver
对象的方法。这在内容提供者和需要信息的组件之间提供了一个抽象层,更加安全。
有以下几个方法启动各个类型的组件:
- 通过传递意图
Intent
对象到startActivity()
或startActivityForResult()
(当你想要活动返回结果时)启动活动或让它执行些新的事情 - 通过传递意图
Intent
对象到startService()
启动一个服务或者为正在运行的服务提供新的指令。或者可以通过传递一个意图Intent
对象到bindService()
绑定到这个服务上。 - 可以通过传递一个
Intent
对象到sendBroadcast()
、sendOrderedBroadCast
或sendStickyBroadcast
发起一个广播通告。 - 可以通过调用
ContentResolver
的query()
方法请求内容提供者。