Android应用程序是基于Java语言写的.Android SDK工具将代码,数据以及资源文件一起编译到一个Android的包里面,然后将其打包为一个有着APK后缀的归档文件.这个拥有这所有代码的APK文件被认为是一个能被Android设备安装的应用程序.
一旦被安装在设备上,每个Android应用程序都存在于自己的安全沙箱中:
1.Android操作系统是一个多用户Linux系统,在这里每个应用程序是一个不同的用户.
2.默认情况下,每个应用程序由系统分配一个唯一的Linux用户ID(ID是系统所使用的,而且不被应用所知).系统给应用中的所有文件都设置权限,只有对应被分配用户ID的应用程序可以访问它们.
3.每个进程都有自己的虚拟机(VM),所以应用程序的运行是与其他应用程序隔离的.
4.默认情况下,每个应用程序在它自己的Linux进程运行.任何应用的组件需要被执行时,Android启动进程,然后当它不再需要时,或者当系统必须恢复其他应用的内存时关闭该进程.
这样,Android系统实现了最小特权原则.那就是,默认情况下,每个应用程序,只能访问一些必须需要工作的组件,而不能访问更多其它的组件.这将创建一个非常安全的环境,当没有允许时,应用程序不能访问的系统部分.
然而,这里有一些方法可以允许应用程序与其他应用程序分享数据,或者是允许应用程序访问系统服务的数据:
1.使两个应用程序共享相同的Linux用户ID,在这种情况下,他们能够访问彼此的文件.为了节约系统资源,具有相同用户ID的应用程序也可以运行在相同的Linux进程,共享相同的虚拟机(应用也必须使用相同的签名证书).
2.应用程序可以申请对设备数据的访问权限,如用户的联系人,短信,可插拔的存储设备(SD卡),摄像头,蓝牙,和更多.所有应用程序的权限必须由用户在安装时授予.
这包括关于如何一个Android应用程序在系统中的基本知识.本文档的其余部分向您介绍:
1.核心框架组件中的应用.
2.为您的应用程序在manifest中声明组件和所需的设备功能.
3.资源文件和代码分开,可以让你的应用更好的来优化设备配置资源.
应用程序组件
应用程序组件是一个Android应用程序的基本构造块.每个组件都是不同的点,通过这些点系统可以进入你的应用程序.不是所有的组件都是为用户和一些互相依赖的实际的切入点,但每一个存在的实体,扮演着特定的角色每个人是一个独特的构建块,帮助你定义你的应用程序的整体行为.
有四种类型的应用程序组件.每个类型都有不同的目的,有不同的生命周期,定义了如何创建和销毁.
这里有四种应用组件:
活动
一个活动代表一个用户界面.例如,一个电子邮件应用程序可能有一个activity显示新邮件列表,另一个撰写邮件的活动,一个活动来读取邮件.虽然活动一起形成一个有凝聚力的电子邮件应用程序的用户体验,每一个都是独立的人.因此,不同的应用程序可以从这些活动的任何一个(如果邮件应用程序允许).例如,一个摄像头应用程序可以在电子邮件应用程序,组成新的邮件开始的活动,为了让用户分享图片.
服务
一个服务是一个组件运行在后台执行长时间运行的操作或执行远程操作.服务不提供用户界面.例如,一个服务可以在后台播放音乐,当用户在不同的应用程序,也可以从网络上获取数据,而不阻塞用户界面和活动.另一个组件,如活动,可以启动服务,并让它运行或绑定到它,与它进行交互.
服务是为服务子类实现,你可以学习更多关于它在 服务 开发者指南.
内容提供者
一个内容提供商管理共享的应用程序数据集合.你可以将数据存储在文件系统中,一个SQLite数据库,在互联网上,或任何其他应用程序可以访问持久存储位置.通过内容提供商,其他应用程序可以查询或修改数据(如果内容提供者允许).例如,Android系统提供一个内容提供者管理用户的联系人信息.因此,任何拥有适当权限的应用程序可以查询内容提供者的部分(如 contactscontract.数据)来读取和写入一个特定的人的信息.
内容提供商也可用于阅读和写作,对应用程序的私有和共享数据.例如,在 笔记本 示例应用程序使用内容提供者保存笔记.
内容提供商作为 ContentProvider子类实现 必须实施一套标准的API,使其他应用程序执行交易.更多信息,见 内容提供商 开发者指南.
广播接收器
一个 广播接收机 是一个组件,响应系统范围的广播公告.许多广播起源于系统例如,广播通知屏幕已经关闭,电池低,或图片拍摄.应用程序也可以进行广播,比如,让其他应用程序知道有些数据已经下载到设备,他们可以使用.虽然广播接收器不显示用户界面,他们可能 创建一个状态栏通知 提醒用户一个广播事件的发生.更常见的是,虽然,广播接收器是一个“门户”的其他组件,只做一点点工作.例如,它可能会启动一个服务来执行基于事件的一些工作.
广播接收机实现为一个类 BroadcastReceiver 每个广播是一个 意图 对象交付.更多信息,见thebroadcastreceiver 类.
Android系统的一个独特的方面是,任何应用程序可以启动另一个应用程序组件.例如,如果你想让用户用照相机拍一张照片,可能有另一个应用程序,应用程序可以使用它,而不是开发活动捕获的照片吧.你不需要包含或者连接到相机的应用程序代码.相反,你可以简单的在相机应用拍摄照片的活动开始.当完成时,照片会返回到你的应用,你可以使用它.对用户来说,相机就好像是你的应用程序的一部分.
当系统启动一个组件,它为应用程序启动的进程(如果它不是已经运行)和实例化该组件所需要的类.例如,如果你的应用程序启动摄像头应用程序截取照片的活动,这些活动是属于摄像头应用程序的过程,而不是在你的应用程序的过程.因此,不像大多数其他系统的应用程序,Android应用程序没有一个单一的入口点(有没有 main() 功能).
由于系统运行文件的权限,限制访问其他应用程序在一个单独的过程,每一个应用程序,你的程序不能直接激活另一个应用程序的组件.Android系统,不过,可以因此激活另一个应用程序的组件,你必须向系统发送一条消息,指定要启动某个组件的你的意图,然后系统激活你的成分.
激活组件
四大组件中的三个组件,服务,和广播接收器是一由一种叫Intent的异步消息来激活的.这些intents在运行时(runtime)将这些属于你的程序或不同程序的单独的组件绑定在一起(bind),你可以把这些intents看作是需要其他组件的action的messengers.
一个intent就是一个Intent对象,这个intent定义了一种可以激活(activate)某个特定组件或者某种特定类型的组件,这两种情况分别对应两种intent的定义方式或者显示的或者隐式的.
对于activities和services,一个intent定义了要执行的操作(action)(比如,要“view”或者“send”什么)和要操作的数据的URI.比如,一个intent可能会为一个activity传递一个请求来展示一张图片或者打开一个网页.有时,你可以启动一个activity来得到返回的结果,在这个例子中这个activity的返回的结果也是一个Intent(比如,你可以发送一个intent让用户选择一个personal contact并返回给你——这个返回的intent就包含了一个指向用户选择的联系人的URI).(关于activity和service的启动方式,下面将介绍)
对于广播接收者来说,intent只是简单的定义了要广播的内容(比如,一个用以表明电池电量很低的广播仅包含了一个表明电池电量很低的字符串).
最后一种组件类型content provider并不是由intent来激活的(activate).而是由接收到ContentResolver的请求时激活的.
它们都各自有自己的方法来激活相应的组件:
1.你可以开始一个活动(或新的东西给它做)通过 意图 到 startactivity() 或 startactivityforresult() (当你想活动的返回结果).
2.你可以启动一个服务(或给予新的指示,一个正在运行的服务)通过 意图 到 startservice().或者你可以绑定到服务通过 意图 tobindservice().
3.你可以通过 意图 方法像 sendbroadcast(), sendorderedbroadcast()发起广播,或 sendstickybroadcast().
4,你可以做一个查询内容提供者在 ContentResolver()调用.
更多的关于intent的内容,可以参看文档中的Intents and Intent Filters. 更多的关于激活特定组件的内容可以参看文档中的:Activities、Services、BroadcastReceiver、Content Providers.
关于Manifest 文件
在Android系统可以启动一个应用程序组件之前,Android系统必须通过读取这个程序的AndroidManifest.xml(即manifest文件)文件来确定要启动的组件存在.你的程序必须在这个manifest文件声明用到的所有的组件,并且这个manifest文件必须在项目的根目录下.
另外,这个manifest文件还声明一些其他的东西,比如:
1.确定这个程序需要的所有权限,比如Internet访问权限或者读取用户联系人权限.
2.声明这个运行这个程序所需要的最低API版本,这个可以根据开发该程序所使用的API版本.
3.声明该程序所需要的硬件或软件特征(features),比如照相机、蓝牙服务或者多点触屏.
4.声明该程序需要链接(link against)的API库(不是Andorid的framework APIs),比如Google Maps library等等.
组件声明
Manifest文件的首要任务就是通知系统关于程序中要使用的组件.比如,一个manifest文件可以用如下的方式来声明一个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属性用于指定一个用于标示该程序的icon.
在<activity>元素中,android:name属性用于确定这个扩展自Activity的子类的全路径名,android:label属性用于标示这个activity的对于用户可见的label.
你必须要用以下方式来声明你的程序组件:
1.activities:<activity>标签
2.services:<service>标签
3.broadcast receiver:<receiver>标签
4.content providers:<provider>标签
如果程序中用到activities、services和content providers,你没有在manifest文件中声明,那么这些组件将不会被系统知道,结果就是你的程序不能运行.然而,broadcast receiver既可以在manifest文件中声明也可以在代码中动态创建(BroadcastReceiver),并通过调用registerReceiver()在系统中注册.
更多关于怎样为你的程序构建manifest文件,请参看文档The AndroidManifes.xml文件.
声明组件的能力
正如在上面Activating Components中讨论的那样,你可以使用一个Intent来启动activities、services和broadcast receiver. 你可以通过在intent中注明目标组件的名字(使用的是组件的类名)来显示的启动组件.然而,intents真正强大的地方在与关于intent的actions的概念.通过intent的actions,你可以简单的描述你要执行的操作的类型(并且可以有选择的描述你要处理的数据),可以允许系统在device中找到这个组件并启动它.如果有多个组件可以执行intent中描述的action,这时用户就可以选择一个来执行.
系统可以识别能对某intent做出反应的方式是通过将接收到的intent和设备中其他程序的manifest文件的intent filters进行比较实现的.
当你在程序的manifest文件中声明一个组件之后,你可以有选择包含intent filters,这些intent filters表明了组件对接收自其他程序的intent做出反应的能力(capabilities).你可以通过添加一个<intent-filter>元素作为a child of the component's declaration element来为你的程序声明一个intent filter.
比如,在一个邮件程序中的一个activity可以编写新的邮件,这样的话你就需要在manifest文件中来声明一个intent filter来对“发送”intent响应(为了发送邮件).这样,在你的程序中,一个activity就可以创建一个发送intent(ACTION_SEND),这样当你调用startaActivity()时,系统就会匹配邮件程序中的发送activity并启动它.
更多关于创建intent filters的内容,可以参看Intents and Intent Filter文档.
声明运行程序所需的条件
Andorid系统可以支持很多不同的设备,并且这些设备的性能特征并不相同.为了防止你的程序被安装在不能正常运行你的程序的较低android系统版本上,通过在manifest文件中声明你的程序支持的设备和软件,便变得尤其重要起来.大多数的这些声明仅是一些信息,而系统并不会读取它们,但是其他的服务比如Android Market却会阅读这些声明来帮助通过通过自己的设备搜索软件的用户过滤软件.
比如,你的程序需要照相机,并且使用的Android2.1的APIs,那么你就必须在你的manifest文件中声明这些需要.这样的话,在Android Market上,没有照相机或者Android系统版本低于2.1将不能安装你的程序.
然而,如果你的程序不需要照相机,你仍可以声明你需要照相机.这种情况下,你的程序必须在运行时做一下检查,来检查这个设备是否含有照相机,如果没有照相机可用,则系统将会使使用照相机的相关程序不能用.
下面是一些你在设计和开发你的程序时,必须要考虑的关于设备的一些重要方面:
屏幕大小和分辨率:
为了根据屏幕的类型进行分类,Android定义了两个特征:屏幕大小和分辨率.
屏幕尺寸有: 小,中,大,超大;
屏幕分辨率类型:低分辨率,中分辨率,高分辨率,超高分辨率;
默认情况下,你的程序可以兼容所有的屏幕尺寸和分辨率,因为Android系统对你的程序的UI布局和image资源做了适当的调整.
输入方式:
很多设备有不同类型的输入方式,比如键盘、轨迹球、五位元导航.如果你的程序需要某特定形式的输入方式,则你必须在manifes文件中使用<uses-configuration>标签来声明.不过这种情况是比较少的.
设备配置:
有许多硬件或软件并不全在Android系统的设备上,比如,一个照相机、光线传感器、某个版本的 OpenGL,或者屏幕的保真度(fidelity).你在任何条件下都不能假定Android设备具备某种特性(feature)(当然得除掉Android标准库的情况),所以如果你的程序使用了某feature,则你必须使用<uses-feature>标签来声明.
平台版本:
不同地 Android 平台设备通常运行不同版本的 Android ,比如 Android 1.6 或者 Android 2.3.每个后续版本通常包含之前版本所不支持的新增 API. In order to indicate which set of APIs are available, 每个平台版本对应一个 API Level (例如, Android 1.0 对应于 API Level 1 , Android 2.3 对应于 API Level 9).如果你使用任何在 1.0 版之后平台新增的 API,你应该使用 <uses-sdk> 元素声明最低 API Level 是包含这些 API的.
为你的应用程序声明所有这些要求至关重要,因为,当你在 Android Market 上发布你的应用程序时,Market 使用这些声明来过滤该应用程序是否对于每台设备可用.这样,你的应用程序仅对能够满足你的应用程序要求的设备可用.
应用程序资源
一个应用程序不仅仅由代码组成——它需要区别于源代码的资源,比如图片,音频文件,以及任何与应用程序视觉呈现相关联的内容.例如,你应该使用 XML 文件定义动画,菜单,风格,颜色,以及 activity 用户界面的布局. 使用应用程序资源文件,可以更容易地更新你的应用程序的特性而无需修改代码,并且 — 通过提供多套可替换资源文件 — 使您能够针对各种设备配置优化你的应用程序(比如不同语言或屏幕大小).
对于你的安卓工程里面包含的每一项资源, SDK 构建工具定义一个唯一的正整数 ID 标识符,你可以使用该标识符从你的应用程序代码中或者从XML文件中定义的其他资源中特指该资源.例如,如果你的应用程序中包含一个名为 logo.png 图片文件(保存在 res/drawable/ 文件夹里), SDK 工具会生成一个资源 ID 命名为 R.drawable.logo,你可以使用该 ID 特指这张图片并插入你的用户界面中.
将资源提供工作同你的源代码分隔开来最重要的原因之一是能够使您为不同的设备配置提供可替换的资源文件.例如,在 XML 中定义 UI 字符串,你可以将这些字符串翻译成其他语言并保存在特定的文件夹中.然后,基于语言 qualifier / 修饰词你添加资源文件夹名称 (比如 res/values-fr/ 对应于法语字符串) 以及用户语言设置, Android 系统会给你的 UI 提供适当的语言字符串.
对于你的可替代资源,Android 支持许多不同的 qualifiers / 修饰符 .修饰符是包含在你的资源文件夹名称中的一个短字符串,以便界定哪些设备配置可使用这些资源. 另一个例子,对于不同的设备屏幕和大小,你应当为你的 activities 创建不同的布局. 例如,当设备屏幕是纵向的 (高),你可能希望一个按钮垂直排列的布局,但当屏幕是横向的(宽),按钮应当水平排列.为了根据方向调整布局,你可以定义两个不同的布局文件并给每个布局文件夹提供适当的修饰符.这样,系统会根据特定的设备方向自动为其提供适当的布局.