原文地址:
http://hkbarton.sacredfir.com/?p=40
前几天已经给大家做过广告了,从这篇开始,我准备每周更新一篇Android研究手记,分享我学习Android开发过程中的一些经验和知识,同时也是给自己进行备忘。由于我研究Android的过程也是我在Android上的第一个完整项目BlogMessage的开发过程,所以我尽量将这个实际项目的开发过程穿插在整个系列中,并试图以此将Google提供的各种文档中比较难理解的部分用尽量简单的方式表达出来。就不继续打广告了,下面进入正题:
学习在一个全新的平台上开发最重要的第一步是什么?我觉得当然不是语言的问题,也更不是工具的问题。学习Windows开发,我们得了解Win32窗口的运行原理,消息队列等机制,不了解这些背后的机制和基本的运行模型,只靠RAD工具我们还是只能停留在普通应用的阶段。学习Web开发,不了解HTML DOM,HTTP协议原理等内容,只靠掌握如ASP.Net,JSP等厂商技术,我们也做不到Web开发的“心想事成”,“胸有成竹”;同样如Anrs Blog中说到的正则表示式的应用,我们还得了解其背后的匹配原理。所以,我觉得面对一个全新的平台,我们得首先了解其工作和运行的基本模型和原理,才能做到以后在这个平台上的“得心应手”。
Android开发平台的架构模型,Google官方已经用一个很简单的结构图清晰的进行了说明,简单来说Android开发平台就是 Linux + Google在其上自己开发的Java虚拟机和运行时 + Android SDK 构成,这些内容供我们了解就可以了。就开发一个完整的Android应用来说,我将对我们十分重要而Google官方文档又说的有些复杂的,关于一个完整的Android程序的静态组成模型,和动态运行时模型,整理成了一张图形如下,我们就从这张图说起:
各位看官先不要被图形中的生词吓死,接下来我会详细解释每一个概念。
先来看图形中的灰色部分,这部分描述了一个完整的Android应用程序可以包含的各个组成部分,我们将组成一个Android程序的组件称为Android Component(图中中间部分的基类),由若干个Android Component就组成了一个完整的Android应用程序。先看图中左下方的Activity,这个组件我们可以认为它是Windows中的窗体概念,这是Android程序的基本组成部分,也就是程序的人机交互界面。比如一个简单的短信程序就应该包含三个Activity,一个短信列表界面,一个阅读短信详细内容的界面和一个编辑短信的界面。图中左上角的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的运行和启动方式等,我会在后续的Post中讲解这些内容)。最后,图中下面中间部分的“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运行时生命周期的关系。