Android的一个核心特性就是一个应用程序可作为其他程序中的元素(那些允许这样的程序提供)。例如,如果你的程序需要用滚动条显示一些图片,另一个程序已经开发出了合适的功能,并且可供其他程序使用,你就可以直接调用那个程序的功能,而不是自己再开发一个。你的程序不需要包含其他程序的代码或者链接到它。而是,当有需要的时候,简单的启动那个程序的一部分功能。
为了能够实现这样的功能,系统必须能够当在需要应用程序中任何一部分的时候启动它的进程,并且实例化那部分的Java对象。为此,不像大多数其他系统中的程序,Android程序不是只有单一的进入点(例如,没有main()函数)。而是,他们拥有系统实例化和运行必须的组件。有四种类型的组件:
Activities
Activity为用户提供了一个可视的用户界面,例如,一个activity展示了一个用户可以选择的菜单列表或显示一些带着标题的照片。一个短信程序可能有一个activity用来显示可以发送信息的联系人,第二个activity用来向选中的联系人写消息,其他的activity用来查看以前的消息,或者更改设置。虽然它们通过聚合性很强的用户界面工作者一起,但是每个activity都独立于其他的。每一个都是 Activity 的子类。
一个应用程序可能只由一个activity组成,或者像刚才提到的短消息程序,它由多个组成。什么是activity,需要多少个,当然取决于应用程序和它的设计。典型的,当应用程序启动的时候,activity中的一个要首先的显示给用户。从一个activity移动到另一个,是用过当前的activity启动下一个来完成的。
每个activity都有一个默认的窗口。一般的情况是,这个窗口填满屏幕,但是他也可以小于屏幕和浮动到其他窗口的上面。activity也可以用作附加的窗口——例如,一个用户调用的弹出式对话框,或者当用户选择屏幕上一个特殊的选项时一个窗口用来显示一些重要的信息。
窗口中的可视内容被一系列层次的视图(view)提供——派生自View类的对象。每个视图都控制了窗口中的 一个矩形区域。父视图包含和组织子视图的布局。叶试图(位于层次中的最底部)绘制在它控制的区域,直接响应这块空间的用户动作。这样,视图就是activity与用户交互的地方。例如,当用户触动一个显示小图片的视图时,会触发一些动作。Android提供了很多现成的视图供你使用——包括按钮,文本框,滚动条,菜单项,复选框还有更多。
整个视图层次通过Activity.setContentView() 方法放到activity的窗口上。 content view是视图层次上的根节点。(更多视图层次的信息请看这个文档 User Interface )。
服务(Services)
服务没有可视化的界面,但是可以无限的运行在后台。例如,服务可以在后台播放音乐同时用户在做着其他的事情。或者他可以通过网络获取数据或计算一些activity需要的东西。所有的服务都继承自Service类。
一个最好的例子是媒体播放器通过一个播放列表来播放歌曲。这个播放器程序或许有一个或多个activity,来允许用户选择音乐和播放它们。然而,音乐本身不能被activity处理,因为用户希望当他们离开播放器窗口去做其他的事情时,音乐仍然能够播放。为了让音乐能够继续,媒体播放器的activity可以启动一个在后台运行的服务。系统应该保证音乐服务运行,即使启动的activity窗口已经不再主屏幕上了。
可以连接到(绑定到)进行中的服务(和开启一个已经不再运行的服务)。当连接上的时候,你可以通过服务暴露的接口和它通信。在音乐服务中,这个接口可以让用户暂停,重定位,停止,重新播放录音。
像activity和其他组件一样,服务运行在应用程序进程的主线程中。所以它们不会阻塞其他组件或用户界面,他们经常为那些比较花费时间的任务产生其他的线程(就像音乐),请看后面的进程和线程
部分。
广播接收器(Broadcast receivers)
广播接收器不会主动做什么事,但是他会接受广播消息并作出响应。许多广播都来源于系统代码
——例如,时区改变的通知,电池底电量,接受到一幅图片,或者用户改变了语言选项。应用程序也能发送消息——例如,让其他的程序知道一些数据已经下载到设备上并且可以使用。
应用程序能拥有任何数量的广播接收器来响应任何消息是很重要的。所有的接收器都集成BroadcastReceiver 类。
广播接收器不会显示用户界面,但是它为了响应一个接受到的消息可能会启动一个activity,或者它会用
NotificationManager来提示用户。通知消息可以有多种方式吸引用户的注意力——闪烁背光灯,振动手机,播放声音,等等。他们一般会在状态栏一直放一个图片,用户可以打开它获得消息。
内容提供器(Content providers)
内容提供器能让把应用程序的数据提供给其他数据。这些数据可以是存储在文件系统中的,也可以是SQLite数据库中的或者其他形式。内容提供器继承自 ContentProvider类,实现了一系列标准的方法来让其他程序接受和存储它控制之下的数据。但是,程序不会直接调用这些方法。而是用一个 ContentResolver 对象,调用它的方法。ContentResolver 可以和任何的内容提供器通信。它和内容提供器一起来管理进程间通信。
更多信息请看这个文档Content Providers。
每当一个请求要被一个特定的组件处理的时候,Android保证这个组件的进程是在运行的,如果需要的话就启动它,这个组件适当的实例是可用的,如果需要会创建这个实例。
触发组件:行为(intents)
当被
ContentResolver最为作为目标时内容提供器被激活。另外三个组件——activity,服务和广播接收器,被叫做行为(intents)的异步消息驱动。行为是一个存放着消息内容的Intent对象。对于activity和服务,它命名请求的动作,指定要处理数据的URI。例如,它可能代表一个给用户显示图片的请求,或者让用户编辑一些文本。对于广播接收器,行为对象为将要传送的消息命名。例如,当摄像头按钮按下的时候,它会发送一些有用的信息。
有各种方法用来触发各类的组件:
- 一个activity通过传递一个行为(intents)对象到 Context.startActivity()或Activity.startActivityForResult()方法来启动(或者有一些新的事情要做)。用来响应的activity可以调用它的 getIntent()方法来获得触发它启动的那个行为(intents)。Android使用activity的onNewIntent()方法来处理后来的行为。
- 一个服务的启动(或者一个新的指令给正在运行的服务),是通过传递一个行为对象到 Context.startService()。Android调用服务的onStart()方法并传递一个行为对象给这个方法。
同样地,行为可以传递给 Context.bindService(),用来建立调用组件和目标服务之间的连接。服务通过onBind()方法的调用来接受行为对象。(如果服务还没有运行,bindService()可以启动它。)例如,一个activity可以和前面提到的音乐播放服务建立连接,因此它可以为用户提供菜单(一个用户界面)来控制音乐播放。这个activity将调用bindService()来建立这个连接,然后调用服务中定义的方法来对音乐播放产生影响。 - 应用程序可以将行为对象传递给这些方法 Context.sendBroadcast(), Context.sendOrderedBroadcast() Context.sendStickyBroadcast()来产生广播消息,
关于行为消息的更多内容,请看这篇文章,
ntents and Intent Filters.
关闭组件
内容提供器仅在响应
ContentResolver的请求的时候触发。广播接收器仅在响应广播消息的时候才有效。所以不必明确的关闭这些组件。
Activity,在另一方面,提供了用户界面。它们在和用户的较长时间的会话中一直都有效,甚至是空闲的时候,只要会话还在继续。同样地,服务也会运行较长的时间。所以Android有一些方法通过逐步的方式停止activity和服务:
- Activity可以通过调用finish() 方法来停止。一个Activity可以通过调用 finishActivity() 方法停止另一个Activity(通过startActivityForResult()方法开启的)。
- 服务可以通过调用它自己的stopSelf()方法停止,或者通过调用 Context.stopService()方法。
组件也可能被系统停止,当他们不再被使用或Android必须为更多的活动中的组件重新分配内存时。后面的一节,组件生命周期,更详细的讨论这个可能性和他的后果。
清单(manifest)文件
在Android启动一个组件之前,它必须能够了解到这个组件的存在。因此,应用程序将它们的组件定义在Android包中的清单(manifest)文件中,这个.apk文件存放着程序的代码,文件和资源。
清单是一个结构化的XML文档,在所有的应用程序中它都以AndroidManifest.xml 命名。它在定义应用程序组件上面做了很多事。像是指定所有应用程序需要链接的库(不包括Android默认的库),还有指定应用程序期望被分配的一切权限。
但是清单文件的主要任务是通知Android关于应用程序组件的信息。例如一个Activity可能会像下面这样这样定义:
<?xml version="1.0" encoding="utf-8"?> <manifest . . . > <application . . . > <activity android:name="com.example.project.FreneticActivity" android:icon="@drawable/small_pic.png" android:label="@string/freneticLabel" . . . > </activity> . . . </application> </manifest>
其他的组件也用类似的方式定义—— <service>元素用来定义服务, <receiver>元素用来定义广播接收器,还有 <provider>元素用来定义内容提供器 。Activity,服务和内容提供器没有定义在清单文件中的话,就不会再系统中可见,最后就不会被运行。但是广播接收器既可以定义在清单文件中,也可以在代码(BroadcastReceiver 对象)中动态创建,然后调用Context.registerReceiver()注册到系统中。
更多关于构建清单文件的内容,请看The AndroidManifest.xml File。
行为过滤器(Intent filters)
行为对象可以明确的指定一个目标组件。如果它这样做,Android寻找(基于清单文件中的定义)这个组件并触发它。但是如果目标没有明确的指定,Android必须找出一个最佳的组件来响应这个行为。它是通过比较行为对象和行为过滤器来找到可能的目标的。一个组件的行为过滤器通知Android那种类型的行为这个组件是能够处理的。像其他组件必须的信息一样,它们定义在清单文件中。这个是前面例子的一个扩展,为Activity添加两个行为过滤器:
<?xml version="1.0" encoding="utf-8"?> <manifest . . . > <application . . . > <activity android:name="com.example.project.FreneticActivity" android:icon="@drawable/small_pic.png" android:label="@string/freneticLabel" . . . > <intent-filter . . . > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter . . . > <action android:name="com.example.project.BOUNCE" /> <data android:mimeType="image/jpeg" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> . . . </application> </manifest>
例子中的第一个过滤器
——动作"android.intent.action.MAIN"和类型 "android.intent.category.LAUNCHER"的组合——很普遍应用的一个。它标志着Activity应该在应用程序启动时运行,那些在屏幕上列出来的用户可以在设备上启动的程序。另一方面,这个Activity是应用程序的入口。这是用户在加载器中选择启动一个应用程序后最先见到的那个。
第二个过滤器定义了应用程序可以运行在一个特定类型数据上的动作。
组件可以有很多行为过滤器,每一个都定义了不同的能力。如果它没有任何过滤器,那么它只能被那些明确的将它设为目标的那些行为所触发。
对那些在代码中创建和注册的广播接收器来说,行为过滤器可以实例化成一个IntentFilter的对象。其他的过滤器都设置在清单文件中。
更多关于行为过滤器的内容请看独立文档, Intents and Intent Filters.