〔原创〕Android的组件编程模型

一、Android应用的理解

对一般的操作系统而言,程序通常就是操作系统中进程的概念。以Windows里面的办公软件Word为例,如图1所示,当启动Word程序后,Windows的任务管理器中会出现一个名为“winword.exe”的进程,而这个winword.exe其实就是MS Office软件包中的一个可执行文件。只是除了这个winword.exe文件之外,还需要若干个依赖的.dll动态链接库文件一起配合才能执行,如图2所示。



 

1 Windows中的进程



 

2 winword.exe程序依赖的动态链接库

 

从这里可以看出,一个Windows系统上的应用程序,可以简单理解为由.exe可执行程序和.dll动态链接库文件共同构成。当应用程序启动加载到内存中,就变成了“进程”的概念了。同样,

 

Linux平台上,一个应用程序也是由一个可执行文件(比如gzip)和若干.so的文件构成,其中.so文件是一些共享对象(shared object)文件,它们的作用与.dll动态链接库是类似的。

 

现在回过头来看看Android平台上的应用程序。当我们开发Android应用程序时,一般需要在ADT集成开发环境中新建一个Android Application Project项目,图3是一个典型的Android项目结构:



 

3 Android项目结构

 

当然,Android项目最终还是要被打包成.apk文件(比如这里的BMI.apk)才能使用,这个.apk表面上看起来与Windows平台上的.exe是类似的,都是用来执行的程序,对Android的初学者而言,这种类比更容易理解。

 

实际上,Android平台的.apk文件的角色,只是承载Android组件的一个载体,.apk并不等同于.exe文件。

二、Android组件模型

我们知道,在开发Android应用程序时,一般都会涉及到AcivityServiceBroadcastReceiverContentProvider这四大组件。那么,到底什么是组件呢?所谓组件,我们可以将它理解成是Android应用程序的组成部分,一个Android应用程序通常都要包括若干个组件,这些组件可以来自于一个apk文件,也可以来自多个apk文件。值得注意的是,这里说的组件概念更为宽泛,并不是一般意义上所说的按钮、下拉框之类的控件,而是一种抽象意义上的“软件单元”。

 

下面使用一张图来对Android平台的组件进行说明,如图4所示。



 

4 Android组件模型

 

Android来说,外部的应用程序通常都是以.apk软件包的形式安装的。在图3BMI项目结构中,共定义了两个Activity组件(BMIActivityInfoActivity),当我们把项目打包成.apk文件并安装到Android系统时,BMIActivityInfoActivity就成了Android系统管理的两个组件了。

 

此时,AcivityServiceBroadcastReceiverContentProvider这四大组件实际上就变成了Android平台上的“积木块”,安装某一个.apk软件包到Android平台,实际上只是往Android平台上安放了几个积木块,如图4所示,这就是Android所谓的“组件”概念。在图4中,X.apk中承载了Activity1Activity2两个组件,Y.apk中承载了Activity3Service1BroadcastReceiver0这三个组件,Z.apk中承载了ContentProvider0这个组件。

 

还记得每个Android应用程序项目都有一个AndroidMenifest.xml文件吗,这个文件其实就是组件的注册文件(类似Windows平台的.reg文件),每个定义的AcivityServiceBroadcastReceiverContentProvider组件都必须在AndroidMenifest.xml中予以声明,否则在Android上是不可用的,至多只是一个普通的Java类而已。当.apk软件包安装到Android中时,Android会读取AndroidMenifest.xml中声明的组件,然后集中管理这些组件,就像Windows注册表所做的那样。

 

一个真正意义上的Android应用程序,其中用到的组件并不一定恰好在一个.apk中,它可以是Android上组件“积木块”的任意组合。比如我们开发了一个应用,这个应用的项目中定义了Activity1Activity2两个组件,然后打包成X.apk安装到Android,但在Activity1的代码中还用到了Activity3组件,这个Activity3组件是Android系统上已经安装好的一个组件(比如Activity1调用Activity3这个照相机组件,而Activity3组件是通过Y.apk安装进来的)。

三、Task栈与Intent组件调用

与传统操作系统不同的是,Android应用程序的概念并不是一个apk,而是一个Task,即任务。所谓Task,就是根据需要将Android平台上的若干组件组合起来,通过这些组件的配合达到预期的目的。Windows中的应用程序体现出来的是“进程”,而Android应用程序体现出来则是“Task”,即任务。当然,Android底层的Linux操作系统上最终的跑的还是进程,但这些进程不是由我们的应用程序直接控制的,所以,Android组件是被托管到进程中运行的。所以,Android应用程序并不与.apk文件一一对应,我们可以根据需要对Android上的组件任意组合,就像搭乐高积木一样,而Android应用包含的各组件在哪个进程中,已经变得不重要了,系统会帮忙处理好一切。

 

一般情况下,当我们运行某个应用程序时,实际上是找到这个应用程序的“起始组件”,通常都是Activity组件,因为只有Activity组件才有可视界面,可以响应用户的操作,然后以起始组件为出发点调用其它组件,从而完成我们希望的功能。在开发Android应用程序时,通常都会声明处理如下动作的Activity组件:

<activity

    android:name="mytest.Activity1"

    android:label="@string/app_name">

     <intent-filter>

          <action android:name="android.intent.action.MAIN" />

          <category android:name="android.intent.category.LAUNCHER" />

     </intent-filter>

</activity>

 

其中,“android.intent.category.LAUNCHER”的含义是允许Android桌面启动器(Launcher)检测应用软件的包名,然后把当前应用的图标和名称解析出来显示在应用列表里。这样,当我们点击桌面启动器的应用程序图标时,声明了“android.intent.action.MAIN”动作的Activity将被启动,类似于Java语言程序的main()方法。

 

顺带提一下,如果你希望自己的应用程序不会在桌面启动器中出现图标,只需将“android.intent.category.LAUNCHER”的声明去掉即可。

 

现在假定应用程序要从Activity1开始启动,然后在Activity1中有一个按钮,点击按钮能启动到Activity2Activity2中也有一个按钮能启动到Activity3,此时,这三个组件就共同完成了当前应用程序的功能。对Android来说,这三个组件是一任务栈的方式进行管理的,如图5所示。



 

5 Android任务栈(应用程序当前组件为Activity3

 

严格来说,由Activity1Activity2Activity3共同形成的任务栈才是Android应用程序的概念。如果当前显示的是Activity3组件,然后点击两次返回键,此时任务栈中就剩下Activity1了,如图6所示。



 

6 Android任务栈(应用程序当前组件为Activity1

 

当然,在任务栈中管理的只是Activity组件,其它组件也可以在应用程序中使用,只不过它们不会出现在任务栈中而已。到现在,我们应该明白Android应用程序是怎么回事,说白了,Android应用程序是由若干组件共同配合所构成的一个动态过程(任务栈),它用到的组件可能来自一个或多个.apk文件中定义的组件。

 

在应用程序中,当你需要启动某个组件时,因为组件是被托管在底层的进程中,因此我们不能直接创建组件的对象,而是通过AndroidIntent意图机制来达到目的。引入Intent的原因,就是因为组件是被托管的,既然是被托管,我们不能直接决定其生死(比如new Activity1()),而是需要构造一个Intenet对象,丢给Android系统,Android系统会根据Intent中提供的意图信息去查找所有注册过的组件,找到后启动该组件。也正是因为Android组件的生死不是有我们来控制的,我们只能向Android请求需要用到某个组件,所以才会出现ActivityService等组件声明周期的说法。

 

下面以Activity1启动Activity2为例来说明Intent的工作原理,如图7所示:



 

通过Intent启动其它组件

    Intent intent = new Intent();

    intent.putExtra("bmi", 1.5);

    intent.setClass(Activity1.this, Activity2.class);

    startActivity(intent);

 

从这里可以看出,我们要启动Activity2,要做的只能是新建一个Intenet对象,然后通过startActivity()方法将这个Intent对象发给Android。当Android收到这个要求时,它会查找符合条件的组件,然后启动这个组件。

 

Android中,通过Intent机制启动组件分为显式启动和隐式启动。这里给的例子就是显式启动,组件Activity1的代码中完全知道Activity2,因此通过intenet.setClass()就提供了所要的组件信息,而且还使用intenet.putExtra()方法将某些数据传递给Activity2组件。而对于隐式启动组件的方法,首先要在配置文件中声明被启动组件Activity2,设置其能够处理的<intent-filter>,然后在调用者Activity1的代码中,就要通过Intent设置希望匹配的动作信息,比如:

        // 调用Web浏览器

        uri = Uri.parse("http://www.google.com");

        intent = new Intent(Intent.ACTION_VIEW, uri);

        startActivity(intent);

 

总之,Android的组件机制要求组件之间不能相互直接调用或使用,因此你不能在Activity1的代码中直接创建一个Activity2的对象(new Activity2()),永远不要这样做!组件之间的调用必须通过Android统一进行调度,有点类似于“中央集权”。组件之间的调用,必须通过Intent,无论是显式Intent还是隐式Intent都是如此。

四、Context的理解

Android应用程序开发时,还有一个经常用到的Context概念,即“上下文”。这个Context就像一只无形的手,很多类和方法的调用都需要借助Context,通过它可以访问当前包的资源(getResources()getAssets()),也能启动其它组件(ActivityServiceBroadcastReceiver),还可以得到各种服务(getSystemService()),因此,实际上Context是提供了应用程序的运行环境,在Context这个大环境里,各个组件才可以访问资源,才能完成和其他组件、服务的交互。

 

我们首先来看一下ContextApplicationServiceActivity等几个常用类之间的关系:



 

8 Context/Activity/Service/Application之间的关系

 

最上面的Context是一个抽象类,下面的ApplicationServiceActivity类都间接继承了这个Context抽象类。ContextWrapper类是Context抽象类的实现者,但它实际上只是一个Context抽象类所要求功能的一个“封装”(抽象类中有抽象方法,子类必须提供抽象方法的实现代码),真正提供具体功能代码的实际上是ContextImpl类,因此ContextImpl类才是那只真正伸向Android核心框架服务的手,ApplicationServiceActivity类可以通过ContextWrapper类间接将手伸向Android核心框架服务。比如向Android要求获取应用程序的资源文件,用到的getResource()方法就是通过ContextWrapper调用ContexImpl的具体方法来得到的。

 

因为ActivityService类都继承了ContextWrapper,换句话说ActivityService组件都是上下文,都有获取系统资源的能力。对于Application,这是一个应用对象,AcivityServiceBroadcastReceiverContentProvider这四大组件都必须在<application>应用对象内部声明才能被Android系统所接受。在ActivityService中要获得这个Application对象,可以通过调用getApplication()得到,此外还可以通过调用getApplicationContext()得到这个Application对象,它同时也代表一个Context

 

值得注意的是,尽管AcivityServiceApplication都是继承自Context,虽然它们都代表Context,但它们并不是同一个,因为各个组件都是独立的。

 

 

参考资料:

http://www.cnblogs.com/android100/p/Android-Context.html

 

 

猜你喜欢

转载自lxh2002.iteye.com/blog/2076270