[Android研究手记1]基本概念和模型

8
Jun
21

前几天已经给大家做过广告了,从这篇开始,我准备每周更新一篇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运行时生命周期的关系。


第一篇手记就写到这里了,下篇预告:《[Android研究手记2] Activity和Service的运行时生命周期模型》。

Filed under: Android
21 Comments

21 Comments

  1. Jimmy
    14:16 on June 8th, 2009

    沙发,哥,我顶你。

  2. anrs
    20:01 on June 8th, 2009

    如果 Android 完全基于 Linux,那能不能进行相关的系统调用喃?

  3. hkbarton
    22:35 on June 8th, 2009

    还没有研究的那么深入…理论上是可行的, ubuntu上马上都可以运行Android程序了.

  4. anrs
    09:14 on June 9th, 2009

    到底 ubuntu 运行 android 程序的意义是啥喃?用 android 框架来当 ubuntu 程序的宿主?还是指在 ubuntu 上搞 android 程序的开发哦?

  5. hkbarton
    12:17 on June 9th, 2009

    让ubuntu运行android程序应该是为了发展上网本吧。

  6. Aaron
    20:44 on June 9th, 2009

    拜读了~

    现在很多上网本的OS直接就是android哈.

  7. hkbarton
    21:57 on June 9th, 2009

    快点把你的blog整好,我们好上去踩哈.

  8. Seth
    09:05 on June 10th, 2009

    支持,现在比较忙,稍后详细拜读一下。:)

    BTW, 你的Blog被广告爬虫给侵犯了。

  9. hkbarton
    11:12 on June 10th, 2009

    对啊,有spam了。。。懒得删了。。。

  10. 小适
    10:54 on June 11th, 2009

    不错不错!我搬板凳来慢慢学习。LZ写得太详细了,佩服。

    于是,一个Android的程序,由UI界面和服务组成,因为可以理解为手机系统也是实时操作系统,当然还是有差异的。然后如果你的程序希望和别的程序交互呢,就可以提供一堆API,就是上图中的Content Provider,如果你的程序还想监听事件,那就在做个Broadcast Receiver就行了。

    期待对Task的更详细的解释。或者,可否把Task理解为一个介于User和Machine之间的操作概念?用户想完成一个查地图的动作,于是,我就有一个查地图的Task,然后所有和查地图相关的,用户需要用到的Activity我都可以往这个Task里面塞,而且我也可以控制各个Activity出现的顺序。

  11. hkbarton
    12:18 on June 11th, 2009

    进程可以理解为对于系统来说的“一个程序”,Task可以理解为对于用户来说的“一个程序”。默认情况下一个Apk包安装运行后就只有一个进程(和Apk包中配置的PackageName相同),这个Apk包中的所有Activity在运行时都默认放到一个Task里面(也和Apk包中配置的PackageName相同)。但是在运行时我们可以把其他进程中的Activity压入我们进程的那个默认Task中。

  12. anrs
    12:21 on June 11th, 2009

    一派欣欣向荣,和谐发展的观快景象…

  13. 小适
    13:18 on June 11th, 2009

    @HKBarton:
    嗯。这样理解行不?我需要在我的程序里让用户输入文字,于是我可以再我的那个Task里面,压入系统自带的用于触摸屏的虚拟键盘的Activity给用户用(当然实际情况可能不会如此,打个比方)。于是,系统的一个Activity也就被压到我当前应用程序的Task中了。
    另外,想问下LZ为何选择了Android?Symbian、Moblin、iPhone的精简版的Mac OS,还有WM,为什么单独看重了Android?^_^

  14. anrs
    13:51 on June 11th, 2009

    楼上的,因为他有支 android 所以就选了 android,如果他有 iPhone 肯定就选 iPhone 了~~~

  15. hkbarton
    17:00 on June 11th, 2009

    @小适:
    你理解的很正确哈
    @All:
    小安说的有道理,因为我买了G1了。但是我也要纠正一下,在我买G1之前就钟情于Android了,小安也晓得撒。至于原因嘛,对比下就知道了:
    1. Symbian用C++,我曾经想尝试,但是放弃了,而且Symbian的授权和证书相当麻烦,还要开发者花钱买,让人很郁闷。
    2. iPhone用Object-C,一样让人头大,而且相对自我封闭,另外就是我没有iPhone嘛!
    3. Moblin: 刚听小安详解了一番,这是一种移动上网设备,貌似于手机没有可比性哈。

  16. UK
    17:40 on June 11th, 2009

    Orz……好多字 ~~

  17. anrs
    20:52 on June 11th, 2009

    楼上明显来围观打酱油的~~~

  18. 小适
    22:35 on June 11th, 2009

    强的!HK同学的这篇的回帖,数量直逼20了!

  19. hkbarton
    22:53 on June 11th, 2009

    就让我来完成这一壮举吧! 20楼!

  20. amiya
    15:50 on June 15th, 2009

    来围观

  21. James
    13:30 on January 23rd, 2010

    不错,一口气读下来,感觉很好。
    Android,iPhone都是个好东西,就差一个好的创意,呵呵。

Sorry, the comment form is closed at this time.