Android 的组件设计

jopen 12年前

    Android的组件设计模型,是Android的程序开发以及理解Android的安全模型的基础。本文总结的开发模型来自http://developer.android.com/guide/components/fundamentals.html

    Android的应用程序,在官方文档定义中,是指APK为后缀文件所包含的代码逻辑被视为一个应用。Android应用由若干组件构成,构成 Android应用的四大组件是:Activity ,Services,Content providers,Broadcast receivers。一个问题是,组件和普通的Android JAVA对象有什么区别?首先,组件必须在Android应用的配置文件中定义,由系统管理的调度,具有独特的生命状态周期,其次,组件是Android 应用安全管理的最小粒度的单元。

    在了解组件的技术细节之前必须先了解组件的运行环境。

Android组件的进程运行环境 

   (1)Android是一种多用户的Linux操作系统,每个应用使用不同的用户ID进行运行。Android对应用的数据文件进行Linux操作层次的权限保护,赋予并仅仅赋予程序用户的ID以访问权限,使用其他用户ID运行的程序无法越权访问程序所保护的数据。

    (2)每个进程有独立的JAVA 虚拟机器,不同的应用隔离在独立的JAVA虚拟机器中。

    (3)缺省的情形下每个应用运行在独立的进程中,当任意一个组件需要运行,Android负责启动应用进程。当进程中所有的应用组件都停止运行,则Android负责停止应用进程,释放资源。

  4)如果两个应用需要紧密耦合的共享应用的数据,需要将两个应用安排在同一个应用进程运行,此时,要求两个应用具有相同的签名。

   

Android的四大组件元素

    在著名的《Inside the Android Application Framework》材料中,将Android的程序构成解释如下:

Android 的组件设计


    Activity是包含显示窗口的基本的Android程序组件,人机交互的基本单元。每个Activity都是android.app.Activity的子类,Activity具有运行时的上下文和独特的生命周期,系统根据需要进行Activity的调度。Activity可以由用户点击系统桌面图标启动或者经由其他应用启动。

    Service组件不包含人机交互的界面,在后台执行某长期工作任务的组件。Service组件可以由应用内部的其他组件启动。Service组件的另一用法是实现绑定IPC(进程间通信)的接口,支持实现远程调用。Service组件支持任意类型的后台任务,包括执行网络事务、播放音乐、后台文件下载等等。

    Service组件非常特殊之处在于其后台运行但是却共用应用的进程空间,并占用主线程(Main Thread)。在官方的开发文档中,对这一点进行了着重的声明,如果需要在Service中执行长期或者高强度的任务,建议创建另外的工作线程来完成, 否则,会拖慢或者阻塞应用进程内的其他Activity类型的组件的响应效率,给用户带来不好的体验。

    Content Provider组件用于管理应用中的可共享的数据,例如,文件、数据库。如果数据仅仅是本应用范围使用,可以不需要Content Provider,直接使用SQLiteDatabase。Content Provider的一个特点是不需要编写访问的客户端,访问时客户端应用在上下文中获取ContentResolver对象,该对象负责与特定的 Content URI对应的Content Provider的通信交互。Android本身也使用Content Provider的机制来保存音频、视频、图像、个人联系人信息。

    Broadcast receivers组件用于接收系统范围内的事件声明,例如,屏幕将被关黑、电池处在低电状态等等。应用也能发起事件广播,用于一些场合,比如说,某数据已经下载完毕,通知相关应用读取等等。虽然Broadcast receivers不包含人机交互的窗口,但是能够Android的状态通知栏来通知用户广播事件的发生。 Broadcast receivers最通常的用法是,接收广播事件之后Broadcast receivers将执行的控制权传递给其他组件,例如,启动Service针对广播事件执行某项任务。


Android组件设计关键特点

   Android组件设计的关键特点是:任意程序都可以启动另一个程序的组件。例如,某团队开发一程序包含打开摄像头并抓拍一张照片,此功能已经有另一应 用的一系列组件完整实现,则团队不需要重新开发一遍,只需要直接使用应用的组件即可。所谓的“直接使用” 甚至不用将已有应用的组件链接进新的程序。这是如何完成的呢,可以从Android组件的通信机制中得到答案。

    从资料中能够总结Android有几种组件通信机制:Intent 机制、IPC Binding机制和ContentResolver。Intent的机制能够唤起Android的三种组件,Activity ,Service ,和Boardcast Receiver  ,是Android组件间主要的通信方式,是一种间接的通信方法。IPC Binding机制是使用远程函数调用的方法与Service组件通信,ContentResolver用于与ContentProvider组件通信。 

Android组件的通信机制

    Intent是一种Android组件间异步事件对象,携带了发送组件的“操作意图”。翻译成自然语言:发送Intent组件期望某个具体的组件(显式指 定)或者期望系统帮忙找合适的组件(隐式指定)完成一项具体的任务,系统找到目标组件后,如果其没有处在运行状态,则负责创建组件、并调度到运行状态执行 指定的任务。Intent机制保证了Android可以最大限度的重用系统的、或者其他安装应用的成熟组件。

   对Activity组件和Service组件来说,接收到的Intent对象包含一个操作(例如,查看View ,发送Send),以及操作对应的数据对象的URI以及必要的参数。举例来说:查看某个图像,打开某个网页等等。一种很常用的用法是,向某个 Activity发送Intent对象要求其完成一项任务并将操作的结果数据包含在一个“Intent”对象返回给发送者。举例来说,许多应用会发送 Intent来完成用户从电话本中选择联系人,并将选择的结果返回。

   对Broadcast receivers来说,其接收的Intent包含广播的事件声明,例如,低电的状态,其Intent仅仅包含一个操作的字符串指明设备正处在低电的状态。

    Service组件能够支持远程函数调用接口,这就是IPC 的Binding 用法。这是Service组件与其他组件通信一种特殊通信方式。

    Content Provider组件不能由Intent唤醒,ContentProvider仅仅与ContentResolver通信,由其唤醒。ContentResolver处理与ContentProvider通信的整个过程,与ContentProvider通信的组件不需要添加额外的逻辑仅仅调用ContentResolver即可。



Android组件组成示例

   下面以一个程序的组件构成实例进行分析。程序的基本功能为:查看好友所在的地理位置,以地图的方式显示,并在附近的好友经过时提示用户。整个人机交互过程涉及三个应用,第一个应用为FriendTracker,跟踪本人以及好友的位置,第二个应用为FriendViewer,查看好友所在位置,第三个应用为系统的联系人应用,用于查看联系人。其组件结构分析如图,其中的浅红色的几何图形代表着某种Android组件,蓝色的几何图形代表普通的JAVA对象,蓝色箭头的线表示某种组件间的通信方式。

Android 的组件设计

    

    整个功能由三个应用完成,第一个应用FriendTracker APP负责跟踪本人以及朋友的地理位置,本人的经纬度信息从本机的LocationManager中获取,朋友的经纬度从网络中心服务器获取。

    FriendTracker APP由一个FrendTracker Activity组件、一个FriendTracker Service组件、以及一个Friend Provider组件构成。FrendTracker Activity组件提供一个人机交互的窗口,让用户启动或者停止“朋友追踪”服务,此时FrendTracker Activity通过startService函数发送Intent启动FriendTracker Service组件

   FriendTracker Service启动后启动LocationManager、启动定时器、启动工作线程从网络获取朋友的地理位置信息,通过FriendProvider写 入数据库,然后由系统调度,可能进入休眠。当定时器到期时会向系统发送一个Intent,这个Intent会唤醒FriendTracker Service ,经唤醒后,再次启动工作线程获取朋友的地理位置信息。当用户的地理位置信息发生变化,则FriendTracker Service计算与每个朋友的位置,如果发现500米内有朋友,则发出一条广播的Intent。该Intent唤起FriendViewer App,APP包含一个FriendViewer Activity,负责从FriendProvider将每个朋友的位置信息读出并显示。从FriendViewer Activity的窗口列表选择朋友的时候,发送Intent触发FriendMap Activity唤醒并显示地图标注朋友所在的位置。当然,也可以从FriendViewer Activity的窗口列表选择朋友查看朋友的详细信息,此时,发送Intent触发了系统的APP应用。

    这里可以看到FriendTracker Service是启动其他线程来完成其工作任务,原因如上文对Service的描述所示。

    而一个整体应用的功能分散在三个子应用中,无疑是为了更好的共享重用、升级管理。

    复杂的是,每一个组件间的通信关系大多都意味着需要权限的管理,特别是跨应用的组件通信。Android的组件的权限管理因此而复杂。这个问题,就留作下次的研究内容。