Android应用的基本组成

来源:互联网 发布:公知精英是什么意思 编辑:程序博客网 时间:2024/05/23 16:54

Android应用的基本组成

l  Android应用是由Java编写的,Android SDK工具把Java代码(可能还和一些数据和资源文件一起)编译为一个Android应用包(apk文件)。Android设备使用这个apk文件来安装应用程序。

一旦程序被安装到Android设备上后,每个程序都会运行在一个独立的安全的沙盘中:

l  Android操作系统一个多用户的Linux系统。每个应用程序表示一个不同的用户。

l  默认情况下,系统会给每个应用程序分配一个唯一的Linux用户标识(User ID)(这些标识仅被系统使用,而应用程序自身是不知道的)。系统会为应用中的所有文件设置权限,这样只有此应用(或者具有此应用的相同User ID的应用)才能访问这些文件。

l  每个进程有着自己的虚拟机,因此应用程序代码在执行的时候是相互独立的。

l  默认情况下,每个应用在自己的 Linux进程中运行。在应用程序的任意组件需要执行的时候,Android系统会启动这个进程。当不再需要此进程(退出应用)或者系统需要为其他应用回收资源(内存等),系统会关闭此进程。

通过这样的方法,Android系统实现了最小权限原则。也就是,每个应用在默认情况下仅能访问它需要的组件。这也就创建了一个非常安全(Google自己说的)执行环境,在这个环境中,应用程序不能访问没有权限的资源。

当然,也有方法可以用来共享应用程序数据和房屋系统服务

l  可以安排两个应用程序拥有相同的用户标识,这样他们可以相互访问对方的文件。为了保护系统资源,有着相同用户标识的应用程序会运行在同一个Linux进程中,也是有同一个虚拟机(这些应用程序必须有相同的证书)。

l  应用程序可以请求访问设备数据(包括:联系人信息,短信,SD卡,照相机等)。这些请求在安装此应用程序的时候由用户授予。

本文档包含了应用程序在Android系统中存在的基本信息,主要包括:

l  应用程序的核心组件

l  应用程序清单文件,主要包含了应用组件的声明和对设置功能的需求

l  独立于应用程序的资源文件(可以使得应用程序在不同的设备配置有最优的效果)

 

应用程序组件

应用程序组件是Android应用的主要组成。每个组件是应用不同的入口点。不是所有的组件都是给用户的入口点,有些组件会依赖于其他组件,但是,每个组件有自己的实体,并扮演一个特定的角色(每个组件是一个唯一的构建单元,用来定义应用的整体行为)。

有四种不同类型的组件,每种类型有着不同的目的,并且有着不同生命周期(组件的创建与销毁)。

下面是四种组件类型:

l  Activities:一个Activity表示一个单一的用户界面。例如,一个邮件应用使用一个Activity来显示新邮件列表,使用另一个Activity来撰写邮件,其他Activity来阅读邮件。虽然这些Activity一起才构成真个邮件应用,但是每一个Activity与其他的是独立的。同样的,其他应用也能够启动这些Activity。例如,一个照相机的应用可以启动一个撰写邮件的Activity来分享照片。一个activity的实现必须是Activity类的子类。

l  Services:一个服务(service)是一个在后台运行的并且执行长时间操作(或者执行远程访问)的组件。服务不需要提供用户界面。例如,当用户在使用其他应用的时候,一个服务可以在后台播放音乐;一个服务能够在后台获取网络数据而不打断用户操作。另外的组件,如activity,能够启动一个服务或者绑定一个服务(和服务交互)。一个服务的实现必须是Service类的子类。

l  Content providers:(内容提供者)一个内容提供者管理了一个共享的数据集合。这些数据可以保存在文件系统、SQLite数据库、网站或者其他存储介质中。通过内容提供者,其他应用程序能够查询甚至修改(如果允许修改的话)这些数据。例如,Android系统实现了一个内容提供者来管理联系人信息。这样,经过授权的应用可以通过这个内容提供者来读取或者修改特定联系人的信息。内容提供者对于读取和写入非共享数据也很有用。例如,Note Pad的实例程序使用一个内容提供者来保存笔记。一个内容提供者的实现必须是 ContentProvider 的子类,并且必须实现一个标准的API集合(实现事务)。

l  Broadcast recerivers:(广播接收器)一个广播接收器是用来响应系统范围内广播消息的组件。许多广播消息来源于系统,例如,屏幕关闭的通知,电量低的通知,图片截取的通知等。应用程序也能够发出广播,例如,通知其他应用数据已经下载完成可以使用。虽然,广播接收器不用显示界面,它们一般会在系统状态栏中创建一个通知图标。一般的,一个广播接收器仅是一个到其他组件的gateway,且只执行很少量的工作,例如,它可以创建一个服务来执行跟多的工作。一个广播接收器的实现必须是BroadcastReceiver类的子类,并且每个广播通知通过一个Intent对象传递。

Android系统设计的一个独特的方面是:任何应用都能启动其他应用的组件。例如,如果需要使用照相机拍摄一张照片,应用程序不需要实现自己实现一个拍照的Activity,而可以使用现有的照相机的组件。在编写程序的时候,甚至不需要和照相机程序进行链接,只需要简单地其他照相机应用对应的Activity就可以了。对于应用的用户来说,照相机就像当前应用的一部分一样。

当系统启动了一个组件,系统会为此应用启动一个进程(如果此应用不在运行)并且初始化此组件所需要的类。例如,如果一个应用启动了照相机应用中拍照的Activity,这个Activity是运行在照相机应用的进程中,而不是当前进程中。因此,和其他的系统的应用不一样,Android应用没有单一的入口点(没main函数)。

因为系统在一个独立的进展中执行应用程序,一个应用不能直接激活另一个应用中的某个组件,而必须通过Android系统。要启动其他应用中的组件,必须发送一个信息给系统,告诉系统要启动特定组件的打算,然后系统会完成启动工作。

激活组件

上面四种组件中的三个(activities, services和broadcastreceivers)能通过一个异步的消息(Intent)来激活。Intent能在运行的时候绑定多个组件,而不管这些组件是否属于同一个应用。

一个Intent由一个Intent对象来描述,它定义了激活特定组件(称为显式Intent)或者激活特定类型组件(称为隐式Intent)的消息。

对于activities和services来说,一个Intent定义了要执行的动作和要操作的数据的URI。例如,一个Intent可能表达一个打开图片或者创建一个网页的请求。在一个情况下,可能需要等待操作的结果,这样,返回的结果也会保存在Intent对象中,例如,应用可以发出一个Intent来请求用户选择一个联系人,那么返回的Intent对象中就包含了所选联系人信息的URI。

对于broadcast receivers,intent定义了被广播的通知,例如,只是设备电量低的广播仅仅包含一个通知字符串("battery is low")。

对于其它组件,content providers,不能通过Intent来激活。如果一个content provider是一个ContentResolver的目标的话,它会被激活。The content resolver handles all direct transactions with thecontent provider so that the component that's performing transactions with theprovider doesn't need to and instead calls methods on the ContentResolver object. 这就在内容提供者和需求信息的组件间增加了一层抽象(为了安全)。

用来激活不同类项组件的方法:

l  通过startActivity()或者startActivityForResult()函数,并且传入一个Intent来启动一个Activity。

l  通过 startService()函数,并且传入一个Intent来启动一个服务。或者通过bindService(),并且传入一个Intent来绑定服务。

l  通过类似于sendBroadcast(), sendOrderedBroadcast()或者sendStickyBroadcast()等函数,并且传入一个Intent来初始化一个广播通知。

l  在一个ContentResolver上调用query()函数来在一个内容提供者上查询数据。

查看Intentsand Intent Filters文档,来获得对于Intent使用的更多信息。对于激活特定组件的更多信息在下面的文档中:Activities, Services, BroadcastReceiver, ContentProviders.

 

清单文件

在Android系统启动一个应用的组件之前,系统必须要知道此组件是否存在。这就通过读取应用程序的清单文件(AndroidManifest.xml)来完成。应用程序必须在这个文件中声明所有的组件,并且这个文件必须在应用程序工程的根目录下。

除了声明应用程序组件外,清单文件还有如下功能:

l  标识需要用户授权的应用程序请求,比如网络连接、读取联系人信息等。

l  声明应用程序所需要的最小的APILevel,也就是生命当前应用程序使用的API。

l  声明应用程序需要或者使用的软硬件,比如照相机、蓝牙服务或者触摸屏等。

l  声明应用程序需要链接的API库,比如GoogleMaps library。

l  等等

 

声明组件

清单文件的主要功能就是让系统知道应用的组件。例如,一个清单文件可以这样声明一个activity :

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:icon="@drawable/app_icon.png" ...>
       <activity android:name="com.example.project.ExampleActivity"
                 android:label="@string/example_label" ...>
       </activity>
       ...
    </application>
</manifest>

在<application>元素中,android:icon属性指向了一个此应用使用的图标资源。

在<activity> 元素中,android:name属性表示了实现此activity 的类的全名;android:label属性指定了此activity 的label。

应用程序必须定义所有的组件:<activity>,<service> ,<receiver> ,<provider>。

那些没有在清单文件中声明的activities、services和content providers对于系统是不可见的,这样也无法运行。但是,broadcast receivers可以通过清单文件来声明,也能够在代码中动态的创建,通过 registerReceiver()向系统注册。

参见TheAndroidManifest.xml File文档,来获得构建清单文件的详细信息。

 

声明组件功能

如上面“激活组件”一节中描述的,应用程序能够发送一个Intent来激活其他组件(不包括内容提供者)。应用程序可以在Intent中显式的指定目标组件(使用目标组件的类名)。但是,Intent的真正功能表现在intent action的概念上。基于intent action,应用程序能够描述要执行的一类动作(可能附加需要操作的数据),然后运行系统来选择当前设备上的一个合适的组件来执行这个动作。如果有多个组件能够执行这个动作,让用户来选择组件。

对于某个指定动作的Intent,系统通过比较其他应用程序的清单文件中intent filters所提供的信息,来确定到底选择哪个组件。

当应用程序在清单文件中声明了一个组件时,可以可选的提供intent filters,来描述此组件能够响应哪些类型的请求。在组件的声明元素中添加一个<intent-filter>子元素,再把具体描述放入此元素内就可以。

例如,一个邮件应用有发生邮件的组件,这个组件在清单中可能会声明一个intent filter来响应发送邮件的动作。其他应用程序能够创建一个发送邮件的Intent action(ACTION_SEND),当应用程序使用这个Intent调用startActivity()的时候,系统会匹配邮件应用的发生邮件的组件并启动它来发送邮件。

查看Intentsand Intent Filters文档,来获得对于Intent filters使用的更多信息。

 

声明应用需求

有许多设备使用了Android系统,但是他们并没有相同的特征和功能。为了防止应用程序在确定特定功能的设备上安装,需要在清单文件中定义应用程序对于硬件和软件的需求。大多数的声明仅仅是提供信息,而系统并不读取它们,但是外部服务,如Android Market,需要读取它们,来辅助用户对应用程序的搜索。

例如,如果一个应用程序需要一个照相机,并且使用了在Android 2.1(API Level 7)中引入的API,那么就需要在清单文件中声明这些需求。这样,那些没有照相机的设备或者版本低于2.1的设备就不能够通过Android Market来安装这个应用程序。

当然,应用程序也能够声明要使用照相机,但并不是依赖它。那么,应用程序可以在运行时候检测设置是否有照相机,然后确定是否执行对应的功能。

有一些重要的设备特征是在开发应用程序的过程中必须要考虑的:

l  屏幕尺寸和密度:为了适应屏幕类型来对设备进行分类,Android系统为设备定义了两个特征:屏幕尺寸(屏幕的物理尺寸)和屏幕密度(屏幕像素的物理密度,DPI)。为了简化不同类型屏幕的设置,Android系统把他们分组来方便选取。屏幕尺寸分为:小,正常,大和超大。屏幕密度分为:低密度,中等密度,高密度和超高密度。默认情况下,应用程序兼容所有的屏幕配置,因为系统会调整UI布局和图片资源的。尽管如此,应用程序应该为特定屏幕尺寸创建特定布局,为特定密度创建特定图片,并且使用可选的布局资源,同时在清单文件的 <supports-screens> 元素中声明它们。更多的信息,请参见 SupportingMultiple Screens文档。

l  输入配置:不同的设备可能提供了不同的输入机制,比如键盘、轨迹球、五方向的导航面板等。如果应用程序需要一个特定类型的输入设备,就需要在清单文件的<uses-configuration>中声明。当然,很少有应用程序需要特定的输入配置。

l  设备功能:在不然的设备上可能有着不同的软硬件功能,比如照相机、光线传感器、蓝牙、特定版本的OpenGL或者触摸屏的保真度等等。应用程序不能假定一个功能绝对存在,应该把所有需要的功能在 <uses-feature>元素中声明。

l  平台版本:不同的设备可能运行着不同版本的Android,如Android1.6,2.3等等。每个连续的版本提供的了前面版本所不支持的额外的API。如果应用程序不是使用Android1.0,就需要在<uses-sdk>中声明使用的API等级。

在清单文件中声明应用程序所有的需求是非常重要的,因为,在通过Android Market发布程序的时候,AndroidMarket会使用这些声明来辅助搜索。

 

应用程序的资源

一个应用不能仅仅有代码组成,它还需要一些独立于代码的资源,比如图片、音频等等。例如,应用程序应该使用XML文件定义动画、菜单、颜色、风格和activity 的界面等。使用应用程序资源能够很简单的更新不同的特性(通过提供不同的资源集合),而不用修改代码。这也可以使得应用在不然的设备配置(语言、屏幕尺寸等)下能够正常运行。

对于每个包含在Android工程中的资源,SDK工具会为它生成一个唯一的整型ID,这样可以在代码中或者XML文件中引用这个资源。例如,应用程序包含一个名为logo.png的图片(在res/drawable/目录),SDK工具会生成一个资源ID名为R.drawable.logo,使用这个ID就能引用这个图片。

相对于代码,独立地提供资源的最重要的一个方面是能在不同的设备配置下选择不同的资源。例如,通过XML定义界面的字符串,这样就能很方便的支持不同的语言,只有提供不同的XML文件即可。通过附加在目录后的语言的限定名称(如res/values-fr/表示法语字符串)和设备的语言设置,系统能够为界面自动的选择合适的语言。

Android支持不同种资源的限定名称。一个限定名称是一个在资源目录名称中的短字符串。这个字符串是用来定义不同设备的的配置的。另一个例子,应用程序可以根据不同的屏幕尺寸和屏幕方向创建不同界面布局。当设备屏幕是纵向的时候,应用程序可能创建的按钮是垂直排列的,而当设备屏幕是横向的时候,应用程序可能创建的按钮是水平排列的。要根据不同的屏幕方向变换布局,应用程序可以定义两套布局,然后为每个布局的目录应用合适的限定名称。这样,系统就会自动的根据当前设备的屏幕方向选择合适的布局。

根据的信息参见ApplicationResources文档

原创粉丝点击