欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android系统架构和应用程序基本概念详解

程序员文章站 2022-04-12 20:21:21
对Android系统应用程序的基本架构进行一个详细了解,对于开发者来说能更有效的开发Android系统应用程序. 对于一个Android应用程序来说,是由四种构造块组织而成的...

Android系统应用程序的基本架构进行一个详细了解,对于开发者来说能更有效的开发Android系统应用程序.

对于一个Android应用程序来说,是由四种构造块组织而成的,这四种构造块如下:

Activity

Intent Receiver

Service

Content Provider

但是,并不是每一个Android系统应用程序都需要这四种构造块,这不是必须的,某些时候,我们只需要这四种中的几种组合成我们的应用。

当我们明确了我们的应用需要哪些构造块后,我们就需要在AndroidManifest.xml中登记这些构造块的清单。这是一个XML配置文件,这个配置文件用于定义我们的应用程序的组件、组件的功能及必要条件等。这个配置文件是每个Android应用必需的。对于AndroidMainfest.xml的Schema,参考SDK包附带的文档。以下,我们对四种构造块做一些说明:

1、Activity

Activity是Android系统应用程序中构造块中最基本的一种,在应用中,一个 activity通常就是一个单独的屏幕。每一个activity都被实现为一个独立的类,并且继承于Activity这个基类。这个activity类将会显示由几个Views控件组成的用户接口,并对事件做出响应。大部份的应用都会包含多个的屏幕。例如,一个短消息应用程序将会有一个屏幕用于显示联系人列表,第二个屏幕用于写短消息,同时还会有用于浏览旧短消息及进行系统设置的屏幕。每一个这样的屏幕,就是一个activity。从一个屏幕导航到另一个屏幕是很简单的。在一些应用中,一个屏幕甚至会返回值给前一个屏幕。

当一个新的屏幕打开后,前一个屏幕将会暂停,并保存在历史堆栈中。用户可以返回到历史堆栈中的前一个屏幕。当屏幕不再使用时,还可以从历史堆栈中删除。默认情况下,Android将会保留从主屏幕到每一个应用的运行屏幕。

Android系统应用程序使用了Intent这个特殊类,实现在屏幕与屏幕之间移动。 Intent类用于描述一个应用将会做什么事。在Intent的描述结构中,有两个最重要的部分:动作和动作对应的数据。典型的动作类型有:MAIN(activity的门户)、VIEW、PICK、EDIT等。而动作对应的数据则以URI的形式进行表示。例如:要查看一个人的联系方式,你需要创建一个动作类型为VIEW的intent,以及一个表示这个人的URI。

与之有关系的一个类叫IntentFilter。相对于intent是一个有效的做某事的请求,一个intent filter则用于描述一个activity(或者Intent Receiver)能够操作哪些intent。一个activity如果要显示一个人的联系方式时,需要声明一个IntentFilter,这个 IntentFilter要知道怎么去处理VIEW动作和表示一个人的URI。IntentFilter需要在AndroidManifest.xml中定义。

通过解析各种intent,从一个屏幕导航到另一个屏幕是很简单的。当向前导航时,activity将会调用 startActivity(Intent myIntent)方法。然后,系统会在所有安装的应用程序中定义的IntentFilter中查找,找到最匹配myIntent的Intent对应的 activity。新的activity接收到myIntent的通知后,开始运行。当startActivity方法被调用将触发解析myIntent 的动作,这个机制提供了两个关键好处:

A、Activities能够重复利用从其它组件中以Intent的形式产生的一个请求;

B、Activities可以在任何时候被一个具有相同IntentFilter的新的Activity取代。

2、Intent Receiver

当你希望你的应用能够对一个外部的事件(如当电话呼入时,或者数据网络可用时,或者到了晚上时)做出响应,你可以使用一个Intent Receiver。虽然Intent Receiver在感兴趣的事件发生时,会使用NotificationManager通知用户,但它并不能生成一个UI。Intent Receiver在AndroidManifest.xml中注册,但也可以在代码中使用 Context.registerReceiver()进行注册。当一个intent receiver被触发时,你的应用不必对请求调用intent receiver,系统会在需要的时候启动你的应用。各种应用还可以通过使用Context.broadcastIntent()将它们自己的 intent receiver广播给其它应用程序。

3、Service

一个Service是一段长生命周期的,没有用户界面的程序。比较好的一个例子就是一个正在从播放列表中播放歌曲的媒体播放器。在一个媒体播放器的应用中,应该会有多个activity,让使用者可以选择歌曲并播放歌曲。然而,音乐重放这个功能并没有对应的activity,因为使用者当然会认为在导航到其它屏幕时音乐应该还在播放的。在这个例子中,媒体播放器这个 activity会使用Context.startService()来启动一个service,从而可以在后台保持音乐的播放。同时,系统也将保持这个service一直执行,直到这个service运行结束。另外,我们还可以通过使用Context.bindService()方法,连接到一个service上(如果这个service还没有运行将启动它)。当连接到一个service之后,我们还可以service提供的接口与它进行通讯。拿媒体播放器这个例子来说,我们还可以进行暂停、重播等操作。

4、Content Provider

Android系统应用程序能够将它们的数据保存到文件中、SQL数据库中,甚至是任何有效的设备中。当你想将你的应用数据与其它的应用共享时,Content Provider将会很有用。一个Content Provider类实现了一组标准的方法,从而能够让其它的应用保存或读取此Content Provider处理的各种数据类型。

Android开发平台的架构模型,Google官方已经用一个很简单的结构图清晰的进行了说明,简单来说Android开发平台就是 Linux + Google在其上自己开发的Java虚拟机和运行时 + Android SDK 构成,这些内容供我们了解就可以了。就开发一个完整的Android应用来说,我将对我们十分重要而Google官方文档又说的有些复杂的,关于一个完整的Android程序的静态组成模型,和动态运行时模型,整理成了一张图形如下,我们就从这张图说起:


先看的Activity,这个组件我们可以认为它是Windows中的窗体概念,这是Android程序的基本组成部分,也就是程序的人机交互界面。比如一个简单的短信程序就应该包含三个Activity,一个短信列表界面,一个阅读短信详细内容的界面和一个编辑短信的界面。
先来看图形中的灰色部分,这部分描述了一个完整的Android应用程序可以包含的各个组成部分,我们将组成一个Android程序的组件称为Android Component(图中中间部分的基类),由若干个Android Component就组成了一个完整的Android应用程序。

图中左上角的Service顾名思议就是服务,一个Android程序中哪些部分是服务呢?举例来说,短信程序并不只是在我们打开短信界面的时候才去收取短信,我们退出界面后,手机仍然会去收取短信,并在新的短信到达时通知我们,所以一定有某个任务在后台运行着,这就是Service了;再比如说音乐播放功能,当我们从播放界面返回手机待机界面的时候仍然可以继续听音乐,这也是一个Service的例子。

其实Activity + Service是非常常见的手机软件应用,比如我要做的BlogMessage同样也是这样的结构。

左边中间部分的“Broadcast Receiver”是用于接收各种系统定义事件或自定义事件的接收器,如果我们的程序想侦测一些系统事件的发生,我们就需要写一个Broadcast Receiver。例如我们的程序想在手机打开Wifi的时候立即去刷新最新的数据,或者我们想在手机来电时执行某个动作,这些都可以由Broadcast Receiver订阅特定的事件来完成。

图中左边剩下的“Content Provider”,我们可以把它理解成一种特殊的Service,一种可以给其他程序提供数据的Service,例如手机中的联系人信息,我们任何程序都可以和其通信去获取联系人的信息,这就可实现为一个典型的Content Provider。
再来看图中蓝色的部分,这是一个静态的部署概念,就如同我们.Net开发的程序集的概念一样。Apk是我们Android程序发布和部署的基本单位,一个完整的Android程序就可以打包为一个或多个Apk进行发布,我们从Android Marketing上下载安装的程序也是一个个的Apk包,我们在Eclipse 中的一个Project的最终Build结果也就是一个Apk文件。一个Apk中包含了上面介绍的4种Android Component。

最后,图中黄色的部分就是系统运行时的概念了。由于Android平台是基于Linux的,所以Process(进程)和Thread(线程)的概念和Linux中的一致,在代码中我们可以编写一个普通的Java Thread来实现多线程。需要注意的是,Android中的Process是受系统自动管理的,并不是说我们在一个程序界面中按了手机上的Back键或者Home键程序就结束了,大家也很难在Android的各种程序中找到类似Symbian程序中的“退出”功能。

Android系统会给每一个进程都计算出一个“重要程度”等级,在系统运行的某个时候例如资源不足的时候,系统会根据各个进程的“重要程度”来决定先释放哪个进程。(进程“重要程度”的判断在Google的官方文档还是说的比较清楚的,实际上各个Android Component都有很完整的运行时生命周期,由于我们不太清楚进程结束的时机,了解各个Android Component的运行时生命周期以及相关事件就对我们的开发来说非常重要,我会陆续在后续的手记中详细阐述这些内容)。一个Apk中包含的Android Component在运行时可以运行在同一个进程中,也可以运行在不同的进程中,这取决于我们在Apk的AndroidManifest.xml上进行的配置(大家可以将这个AndroidManifest.xml看成是Apk的全局配制信息,其中会描述这个Apk中包含了哪些Android Component以及各个Component的运行和启动方式)。

最后,图中下面中间部分的“Task”是Android中一个很特殊的运行时概念,也是很复杂的一个概念,Google的官方文档用了很大的篇幅来说明这个概念。它有别于进程和线程,并且只和Activity的运行时有关系。我们可以将其理解成“窗口栈”,这是由手机上的特殊操作方式所引出的概念。

由于手机上的程序,用户一般只能在同一时间看到一个界面,例如在编辑短信的时候一般就不能看到短信列表的界面。而一个完整的程序一般会由多个Activity组成,所以这些Activity会在运行时随着打开的先后顺序会被放到同一个窗口栈(Task)中,当前活动窗口栈中最上面的Activity就是用户当前看到的界面,按手机上的“Back”则是销毁当前栈顶的Activity,回到上一个界面。然而Task这个概念之所以复杂,是因为不同Process中的Activity可以被放到同一个Task中,例如在我们的程序中可能会打开Google Map的地图界面。

具体Activity在运行时该被放到哪个Task中,这会由Activity的taskAffinity属性决定,一般情况下一个Apk中的所有Activity在运行时会被放到同一个Task中,但是运行时Activity的taskAffinity是可以修改的。例如上面说的Google Map的例子,地图显示界面默认是存在于Google Map这个程序的默认Task中的,但是我们却可以在运行时将这个界面带到我们自己程序的当前Task中来。

窗口在Task中的“入栈”和“出栈”操作和Activity的运行时生命周期息息相关,后面我也会用更详细的篇幅来介绍Task和Activity运行时生命周期的关系。

Android系统架构和其操作系统一样,采用了分层的架构。Android分为四个层,从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和linux核心层。

Android系统架构之Linux 内核

Android构建在一个稳定且得到广泛认可的基础之上:Linux内核。1991年,Linus Torvalds开发了Linux内核。现在,Linux可以说是无所不在,从手表到超级计算机中都能发现它的身影。Linux为Android提供了硬件抽象层,以便将来可以把Android移植到更多的平台上。

Android 的核心系统服务依赖于 Linux 2.6 内核,如安全性,内存管理,进程管理, 网络协议栈和驱动模型。 Linux 内核也同时作为硬件和软件栈之间的抽象层。

开发期间需要的某些实用程序要和Linux打交道。例如,adb shell命令 将打开一个Linux shell,从中可以输入要在设备上运行的其他命令。例如,可以通过这个shell来检查Linux文件系统、查看活动的进程等,但有一定的安全限制。

Android系统架构之系统运行库

Linux内核层上面的一层中包含了Android的本机库。这些共享库都是用C或C++语言编写的,并且针对手机使用的特定硬件架构进行了编译,并已由手机制造商预先安装到手机中。

1)程序库

Android 包含一些C/C++库,这些库能被Android系统中不同的组件使用。它们通过 Android 应用程序框架为开发者提供服务。以下是一些核心库:

* 系统 C 库 - 一个从 BSD 继承来的标准 C 系统函数库( libc ), 它是专门为基于 embedded linux 的设备定制的。

* 媒体库 - 基于 PacketVideo OpenCORE;该库支持多种常用的音频、视频格式回放和录制,同时支持静态图像文件。编码格式包括MPEG4, H.264, MP3, AAC, AMR, JPG, PNG 。

*界面管理器(Surface Manager)- 对显示子系统的管理,并且为多个应用程序提 供了2D和3D图层的无缝融合。Android使用与Vista或Compiz类似的组合窗口管理器,但是它要更简单一些。它并不是将显示内容直接绘制到屏幕缓冲区中,而是将绘制命令传递给屏幕外的位图,然后将该位图与其他位图组合起来,形成用户看到的显示内容。这种方法允许系统实现所有有趣的效果,如透明的窗口和奇特的过渡效果。

* LibWebCore - 一个最新的web浏览器引擎用,支持Android浏览器和一个可嵌入的web视图。

* SGL - 底层的2D图形引擎

* 3D libraries - 基于OpenGL ES 1.0 APIs实现;该库可以使用硬件 3D加速(如果可用)或者使用高度优化的3D软加速。

* FreeType -位图(bitmap)和矢量(vector)字体显示。

* SQLite - 一个对于所有应用程序可用,功能强劲的轻型关系型数据库引擎。

2)Android 运行库

Android 包括了一个核心库,该核心库提供了JAVA编程语言核心库的大多数功能。

每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚拟机实例。Dalvik被设计成一个设备可以同时高效地运行多个虚拟系统。 Dalvik虚拟机执行(.dex)的Dalvik可执行文件,该格式文件针对小内存使用做了优化。同时虚拟机是基于寄存器的,所有的类都经由JAVA编译器编译,然后通过SDK中 的 “dx” 工具转化成.dex格式由虚拟机执行。

Dalvik虚拟机依赖于linux内核的一些功能,比如线程机制和底层内存管理机制。

Android系统架构之应用程序框架

开发人员也可以完全访问核心应用程序所使用的API框架。该应用程序的架构设计简化了组件的重用;任何一个应用程序都可以发布它的功能块并且任何其它的应用程序都可以使用其所发布的功能块(不过得遵循框架的安全性限制)。同样,该应用程序重用机制也使用户可以方便的替换程序组件。

隐藏在每个应用后面的是一系列的服务和系统, 其中包括;

* 丰富而又可扩展的视图(Views),可以用来构建应用程序, 它包括列表(lists),网格(grids),文本框(text boxes),按钮(buttons), 甚至可嵌入的web浏览器。

* 内容提供器(Content Providers)使得应用程序可以访问另一个应用程序的数据(如联系人数据库), 或者共享它们自己的数据

* 资源管理器(Resource Manager)提供非代码资源的访问,如本地字符串,图形,和布局文件( layout files )。

* 通知管理器 (Notification Manager) 使得应用程序可以在状态栏中显示自定义的提示信息。

* 活动管理器( Activity Manager) 用来管理应用程序生命周期并提供常用的导航回退功能。