Android独特的应用组件架构在某种程度上是Android多处理并发的产物。为了使该环境能够适应多个供应商的多种应用,信任每个供应商只需要很少的工作,Android执行Dalvik VM的多个实例,每个任务执行一个实例。在P83“组件生命周期”一节以及后续的章节中,我们将探讨组件生命周期如何促进Android提高应用堆内的垃圾收集工作,以及如何促进多个堆之间的内存回收策略。
由于这种简单而又可靠的多处理方式,Android必须高效地把内存划分成多个堆。每个堆相对较小,这样内存可以支持多个应用同时运行。在每个堆中,由于有了组件生命周期而使得不使用的组件,尤其是当前不活跃的用户界面组件,在堆的空间紧张时能够执行垃圾回收,而在需要时能够重新获取。因此,由这种方式又引入了以数据库为中心的数据模型,其中大部分数据都是内在持久的,关于这一点本书后面将会更加详细地讨论,尤其是第10章。
Dalvik虚拟机
Android的多路处理利用了虚拟机的多进程和多实例,需要虚拟机的每个实例都能有效利用空间。这是通过组件生命周期来完成的,它使得对象某种程度上能够通过虚拟机本身执行垃圾回收和重新创建。Android通过Dalvik虚拟机运行特地为Android开发的字节码系统,该字节码系统名为dex。dex字节码的空间效率几乎是Java字节码的两倍,对于每个进程,从根本上看,在内存消耗上仅为Java类的一半。Android系统还使用写时复制(copy-on-write)的内存管理方式来实现同一个Dalvik可执行文件的多个实例之间的堆内存的共享。
Zygote:派生新的进程
当每个新的进程启动虚拟机的一个新的实例时,如果每次都加载所有必要的基类,则效率会很低。由于Android把每个应用放在独立的进程中,它会利用底层Linux操作系统的fork操作,通过模板进程生成新的进程,该进程在启动新的虚拟机实例时能够达到最优状态。该模板进程的名字就是Zygote。Zygote模板进程是Dalvik虚拟机的一个实例,它包含一组预加载类及Zygote进程的其他状态,这些进程通过fork操作生成Zygote的副本。
沙盒:进程和用户
Android的安全在很大程度上依赖于Linux操作系统层的安全机制,尤其对于进程和用户级别的边界限制。由于Android面向的是个人设备,即个人持有和使用的设备,Android巧妙地利用了Linux内在的多用户支持特性:为每个应用供应商创建一个单独的用户。这意味着每个应用以不同的用户权限运行(除了那些来自同一个供应商的)。在默认情况下,一个应用所拥有的文件,其他应用是无法访问的。
这就类似于在Windows系统上,你以自己的用户名运行Word程序,而以同事的用户名运行Web浏览器。无论要切换查看Word还是Web浏览器,都需要首先退出,然后切换用户才能查看,而无法同时查看。Android允许一个登录的手机用户查看以不同的Linux级别用户运行的多个应用。
这种方式带来的直接影响是由于每个应用在自己的“独立运行空间(silo)”中执行,因而安全性得到了提高。
桌面操作系统通常不会如此全面地考虑应用的沙盒特征——一旦安装了某个应用,用户的所有数据都会信任该应用。Android设计师们设想的是来自众多供应商的很多小的应用,这些供应商并非都是完全可信的。因此,一个应用无法直接访问其他应用的数据。
关于Android安全性的完整描述可以在Android文档中获取:http://developer.android.com/guide/topics/security/security.html。
Android库
Android引入了一些新的软件包,这些软件包和传统的Java(J2SE)软件包一起组成了Android运行时环境API。我们一起来看看这些API组合包含了哪些内容。
Android和dalvik
这些软件包括了Android运行时环境中Android专有的所有部分。本书的大部分主题都是围绕着这些库展开的,具体包括:Android GUI和文本处理库(android.graphics、android.view、android.widget和android.text),以及应用框架库,名为android.app、android.content和android.database。此外,还包含一些其他核心的、面向移动的框架,如android.telephony和android.webkit。熟练的Android程序员至少应该对前面几个包非常熟悉。可以按照Android软件包的树形透视图来遍历Android文档,可以从下面这个地址中Android开发者文档的最上方开始查看:http://developer.android.com/reference/packages.html。
java
Java这个软件包包含核心Java运行时库的实现。java.lang包包含类Object的实现,类Object是所有Java对象的基类,java.util包包含Java集合框架:Array、Lists、Map、Set和Iterator及它们的实现。Java集合库(Java Collections Library)提供了Java语言的一组精心设计的数据结构——有了它们你不需要编写自己的链表数据结构。
如第2章所述,java.util包包含了源于两个不同谱系的集合,一些是源于Java 1.1,另一些是源于更新版本的Java的集合重新设计理念。Java 1.1中的集合(如Vector和Hashtable)是完全同步的,并且其接口不是很一致。新版本的Java中的集合(如HashMap和ArrayList)不是同步的,一致性更好,因此是编程人员的首选。
为了保持和Java语言的兼容性,Android库也包含一些遗留类的实现,但应尽量避免使用这些类。举个例子,Collections框架包含类Dictionary,该类已经显式废弃。Enumeration(枚举)接口已经被Iterator(迭代器)取代,TimerTask已经被Concurrency框架中的ScheduledThreadPoolExecutor取代。Android参考文档很清楚地标识出了这些遗留类型。
java还包含一些其他经常用到的对象(如Currency、Date、TimeZone和UUID)的基本类型,以及I/O、网络、并发和安全的基础框架。
在Android版本的java包层次结构中,不包含awt包和rmi包。awt包被Android的GUI库所取代。远程消息机制(RMI)并没有与其一一对应的替换者,但是内部的ServiceProviders使用了Parcelables,如P116“序列化”一节所述,提供了类似的功能。
javax
javax包和java包非常相似。它包含Java语言的一部分官方实现。javax库的行为是完全明确的,但是它不是Java语言的完整实现的一部分。因为Android运行时环境并不包含一些必需的部分,和Android包存在一定的区别,但还是尽可能看起来和Java包一样。javax包和Android包的树形结构都包含了组成Java语言的库的实现。
javax包中最重要的实现是XML框架。XML框架包含SAX和DOM解析器、XPath的实现,以及XSLT的实现。
此外,javax包还包含了一些重要的安全扩展和OpenGL API。一个经验丰富的Java开发人员会注意到javax包中缺少了Android运行时环境实现的一些重要部分,尤其是那些和UI以及多媒体相关的部分。Javax不包含javax.swing、javax.sound以及其他类似的部分。这些部分都由Android特定的包所取代。
org.apache.http
org.apache.http软件包树包含标准的Apache HTTP客户端、服务器和HttpCore的实现。该软件包提供了使用HTTP进行通信的所有必须功能的实现,包括表示消息、头、链接、请求和响应的所有类的实现。
Apache HttpCore项目的更多信息可以在下面这个页面中查看:http://hc.apache.org/httpcomponents-core/index.html。
org.w3c.dom、org.xml.sax、org.xmlpull和org.json
这些包是一些常用的数据格式的公共的API定义:XML(http://www.w3,org/standards/xml/)、XML Pull(http://www.xmlpull.org/index.shtml)和JSON(http://www.json.org/)。