
2.3 剖析Android系统架构
“剖析”二字听上去有一点点暴力,具有“解剖分析”之意,是指对一个人或一件事做深入的分析,让别人了解这个人或明白事情的来龙去脉。学习Android之路是注定不平坦的,需要我们付出一定的时间和精力。为了更加深入理解Android的精髓,我们很有必要了解Android的系统架构,了解它的组成。只有这样才能知道Android究竟能干什么,我们所要学的是什么。
2.3.1 Android体系结构介绍
Android是一个移动设备的开发平台,其软件层次结构包括操作系统(OS)、中间件(MiddleWare)和应用程序(Application)。根据Android的软件框图,其软件层次结构自下而上分为以下4层。
(1)操作系统层(OS)
(2)各种库(Libraries)和Android运行环境(RunTime)
(3)应用程序框架(Application Framework)
(4)应用程序(Application)
上述各个层的具体结构如图2-19所示。

图2-19 Android操作系统的组件结构图
1. 操作系统层(OS)——最底层
因为Android源于Linux,使用了Linux内核,所以Android使用Linux 2.6作为操作系统。Linux 2.6是一种标准的技术,Linux也是一个开放的操作系统。Android对操作系统的使用包括核心和驱动程序两部分,Android的Linux核心为标准的Linux 2.6内核,Android更多的是需要一些与移动设备相关的驱动程序。主要的驱动如下所示:
■ 显示驱动(Display Driver):常用基于Linux的帧缓冲(Frame Buffer)驱动;
■ Flash内存驱动(Flash Memory Driver):是基于MTD的Flash驱动;
■ 照相机驱动(Camera Driver):常用基于Linux的v4l(Video for )驱动;
■ 音频驱动(Audio Driver):常用基于ALSA(Advanced Linux Sound Architecture,高级Linux声音体系)驱动;
■ WiFi驱动(Camera Driver):基于IEEE 802.11标准的驱动;
■ 键盘驱动(KeyBoard Driver):作为输入设备的键盘驱动;
■ 蓝牙驱动(Bluetooth Driver):基于IEEE 802.15.1标准的无线传输技术;
■ Binder IPC驱动:Android的一个特殊驱动程序,具有单独的设备节点,提供进程间通信的功能;
■ Power Management(能源管理):管理电池电量等信息。
2. 各种库(Libraries)和Android运行环境(RunTime)——中间层
本层对应一般嵌入式系统,相当于中间件层次。Android的这一层分成两个部分:一个是各种库,另一个是Android运行环境。本层包含的各种库如下所示。
■ C库:C语言的标准库,也是系统中一个最底层的库,C库是通过Linux的系统调用来实现的;
■ 多媒体框架(MediaFrameword):这部分内容是Android多媒体的核心部分,基于PacketVideo (即PV)的OpenCORE,从功能上本库一共分为两大部分:一个部分是音频、视频的回放(PlayBack),另一部分则是音视频的录制(Recorder);
■ SGL:2D图像引擎;
■ SSL:即Secure Socket Layer位于TCP/IP协议与各种应用层协议之间,为数据通信提供安全支持;
■ OpenGL ES 1.0:提供了对3D的支持;
■ 界面管理工具(Surface Management):提供了管理显示子系统等功能;
■ SQLite:一个通用的嵌入式数据库;
■ WebKit:网络浏览器的核心;
■ FreeType:位图和矢量字体的功能。
Android的各种库一般是以系统中间件的形式提供的,它们均有一个显著特点就是与移动设备的平台的应用密切相关。
Android运行环境主要是指虚拟机技术——Dalvik。Dalvik虚拟机和一般Java虚拟机(Java VM)不同,它执行的不是Java标准的字节码(Bytecode ),而是Dalvik可执行格式(.dex)执行文件。在执行的过程中,每一个应用程序即一个进程(Linux的一个Process)。二者最大的区别在于Java VM是以基于栈的虚拟机(Stack-based),而Dalvik是基于寄存器的虚拟机(Register-based)。显然,后者最大的好处在于可以根据硬件实现更大的优化,这更适合移动设备的特点。
3. 应用程序(AppIication)
Android的应用程序主要是指用户界面(User Interface)方面的应用,通常用Java语言编写,其中还可以包含各种资源文件(放置在res目录中)。Java程序和相关资源在经过编译后,会生成一个APK包。Android本身提供了主屏幕(Home),联系人(Contact),电话(Phone),浏览器(Browers)等众多的核心应用。同时应用程序的开发者还可以使用应用程序框架层的API实现自己的程序。这也充分体现了Android开源的巨大潜力。
4. 应用程序框架(AppIication Framework)
Android的应用程序框架为应用程序层的开发者提供APIs,它实际上是一个应用程序的框架。由于上层的应用程序是以Java构建的,因此本层次所提供的内容首先包含了UI程序中所需要的各种控件,例如:Views(视图组件),其中又包括了List(列表),Grid(栅格),Text Box(文本框),Button (按钮)等。甚至还有一个嵌入式的Web浏览器。
一个基本的Android应用程序可以利用应用程序框架中的以下五个部分。
■ Activity(活动)
■ Broadcast Intent Receiver(广播意图接收者)
■ Service(服务)
■ Content Provider(内容提供者)
■ Intent and Intent Filter(意图和意图过滤器)
本书的目的是讲解Android应用开发的知识,其内容在结构图中和应用程序(Application)相对应,所以读者们需要重点关注应用程序框架(Application Framework)的知识。这些知识都是用Java开发的,当然也还需要掌握一些其他层的相关知识,例如底层的内核和驱动等知识。
2.3.2 Android应用工程文件组成
了解Android的整体结构之后,接下来开始讲解Android工程文件的组成。
在Eclipse中,一个基本的Android项目的目录结构如图2-20所示。

图2-20 Android应用工程文件组成
1. src目录——程序文件
在里面保存了我们程序员辛辛苦苦直接编写的程序文件。和一般的Java项目一样,“src”目录下保存的是项目的所有包及源文件(.java),“res”目录下包含了项目中的所有资源。例如,程序图标(drawable)、布局文件(layout)和常量(values)等。不同的是,在Java项目中没有“gen”目录,也没有每个Android项目都必须有的AndroidManfest.xml文件。
“.java”格式文件是在建立项目时自动生成的,这个文件是只读模式,不能更改。R.java文件是定义该项目所有资源的索引文件。例如下面是某项目中R.java文件的代码。
package com.yarin.Android.HelloAndroid; public final class R { public static final class attr { } public static final class drawable { public static final int icon=0x7f020000; } public static final class layout { public static final int main=0x7f030000; } public static final class string { public static final int app_name=0x7f040001; public static final int hello=0x7f040000; } }
在上述代码中定义了很多常量,并且这些常量的名字都与res文件夹中的文件名相同,这再次证明.java文件中所存储的是该项目所有资源的索引。有了这个文件,在程序中使用资源将变得更加方便,可以很快地找到要使用的资源,由于这个文件不能被手动编辑,所以每当我们在项目中加入了新的资源时,只需要刷新一下该项目,.java文件便自动生成了所有资源的索引。
2. AndroidManfest.xmI文件——设置文件
文件AndroidManfest.xml是一个控制文件,在里面包含了该项目中所使用的Activity、Service和Receiver。例如下面是某项目中文件AndroidManfest.xml的代码。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yarin.Android.HelloAndroid" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".HelloAndroid" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="9" /> </manifest>
在上述代码中,intent-filter描述了Activity启动的位置和时间。每当一个Activity(或者操作系统)要执行一个操作时,它将创建出一个Intent的对象,这个Intent对象可以描述你想做什么,你想处理什么数据,数据的类型,以及一些其他信息。Android会和每个Application所暴露的intent-filter的数据进行比较,找到最合适Activity来处理调用者所指定的数据和操作。下面我们来仔细分析AndroidManfest.xml文件,如表2-1所示。
表2-1 AndroidManfest.xmI分析

3. 常量的定义文件——露脸的文件
下面我们看看在资源文件中对常量的定义,例如文件String.xml的代码如下所示。
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World, HelloAndroid!</string> <string name="app_name">HelloAndroid</string> </resources>
上述常量定义文件的代码非常简单,只定义了两个字符串资源,请不要小看上面这几行代码。它们的内容很“露脸”,里面的字符直接显示在手机屏幕中,就像动态网站中的HTML一样。
在Android还有一个露脸的文件,那就是布局(layout)文件,这个文件一般位于“res\layout\main.xml”。虽然它里面的字符没有“露脸”,但是里面的代码能够生成一个显示界面。例如下面的代码。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout>
在上述代码中,有以下几个布局和参数。
■ <LinearLayout></LinearLayout>:在这个标签中,所有元件都是按由上到下的队列排列的。
■ android:orientation:表示这个介质的版面配置方式是从上到下垂直地排列其内部的视图。
■ android:layout_width:定义当前视图在屏幕上所占的宽度,fill_parent即填充整个屏幕。
■ android:layout_height:定义当前视图在屏幕上所占的高度,fill_parent即填充整个屏幕。
■ wrap_content:随文字栏位置的不同而改变视图的宽度或高度。
在上述布局代码中,使用了一个TextView来配置文本标签Widget(构件),其中设置的属性android:layout_width为整个屏幕的宽度,android:layout_height可以根据文字来改变高度,而android:text则设置了这个TextView要显示的文字内容,这里引用了@string中的hello字符串,即String.xml文件中的hello所代表的字符串资源。hello字符串的内容“Hello World, Hello Android!”就是我们在HelloAndroid项目运行时看到的字符串。
注意
上面介绍的文件只是主要文件,在项目中需要我们自行编写。在项目中还有很多其他文件,它们大多不需要我们编写,所以在此就不进行讲解了。