应用程序基础
一旦安装在设备上之后,每个Android应用程序运行在它自己的安全的沙箱中:
- Android操作系统是多用户Linux系统,每个程序是一个不同的用户。
- 系统会分配每个应用程序一个独立的Linux用户ID(这个ID只会被系统使用,而应用程序是不需要关心的)。系统会使用这个独一无二的用户ID来设置程序文件的权限,所以只有拥有这个用户ID的应用程序才可以访问这些文件。
- 每个进程运行在自己的虚拟机中,所以应用程序各自互补干扰。
- Android系统启动需要的进程,然后关闭不需要的进程。
Android系统实现的是最精简原则。它创建了一个安全的环境,如果没有获得授权,应用程序是无法访问的。
然而,这里有一些方法与其他的应用程序共享数据:
- 两个应用程序共享同一个Linux用户ID,他俩就可以相互访问对方的文件。为了节省系统资源,相同ID的程序可以运行在相同的Linux进程中并且共享同一个虚拟机(程序必须使用同一签名)
- 应用程序对设备数据发出申请,例如:联系,短信,SD卡,摄像头,蓝牙,等等。所有的权限在安装的时候被授权
应用程序组件
组件是Android程序最重要的基石。每个组件都有一个不同的入口点。但不是所有组件是用户访问的入口点。这里有四种不同类型的应用组件。每种类型起着不同的作用,有着不同的生命周期
-
Activities 活动
- 活动可以由与用户交互的用户界面来代表。例如,邮件应用会有一个显示邮件列表的活动,一个写邮件的活动,一个读邮件的活动。虽然三者一起构成了整个邮件应用程序,但是他们之间又是相互独立存在的。不同的应用程序能够启动任何一个其他程序的活动。例如,摄像头程序可以启动一个邮件的活动去发送分享含有图片的邮件。
-
Services 服务
- 服务是一个组件,一直运行在后台执行任务。服务是没有用户界面的。例如,一个运行在后台播放音乐的服务,一个运行在后台从网络上收集数据的服务。
-
Content providers 内容提供者
-
内容提供者管理共享的应用数据。你可以把数据存储在文件系统上,SQLite数据中,web,或者任何一个持久化的地方。通过内容提供者,其他应用程序可以查询或者甚至修改本应用程序的数据。我们也可以使用内容提供者来读写程序的隐私数据内容。
- 广播接收者是一个能够接收系统范围内的广播通知的组件。许多广播消息来源于系统本身,例如,屏幕关闭,电力不足,照片捕获。应用程序也可以发出广播消息,例如,通知其他应用程序某些数据已经下载完成。尽管广播接收者没有用户界面,但是他们也可以在消息到达后,通过状态通知栏提示用户。一般来讲,我们可以将广播接收者比喻为一个网关。它可以在收到某种特定的消息后,开启某项服务。
Android系统构架中有个独一无二的特点就是任何应用程序都能够启动另外一个应用程序的组件。例如,你想在你的程序中增加一个拍照的功能,由于别人已经开发了一个这样拍照的应用,那么你就不需要再重复劳动开发。而且你都不必在你的程序代码中插入引用外部程序的链接,非常简单地就可以启动拍照程序。当拍照结束,这张照片就可以回到你的程序中,然后就可以随你所用。对于用户来讲,这个拍照功能就是这个程序原生的组件。
当系统启动一个组件,一个进程就会被启动,并且相应类的对象会被实例化。例如,如果你的应用开启了一个拍照程序,那么这个活动就是运行在拍照程序进程中,而不是你的应用程序中。因此,不像其他应用程序,Android系统没有一个单一的入口(没有main函数)。
因为应用程序相互之间有访问权限的问题,所以你的应用程序不能直接激活其他应用程序的组件。所以在Android系统中,为了启动另外一个程序组件,你必须发送一个intent消息激活一个特定的组件,系统会帮你处理这个消息完成激活的工作。
激活组件
四种组件类型中有三个是通过叫做intent的一个异步消息激活的,它们分别是活动,服务和广播接收者。在运行过程中,Intent将这些独立的组件绑定在一起。
一个intent消息就是一个Intent的对象实例,它指定了是去激活一个特定的组件还是一种特定类型的组件。
对于活动和服务组件来讲,intent会定义执行的动作,并且可以指定动作所需的数据URI。
对于广播接收者组件来讲,intent只要简单的定义一下通知的内容.
另外一种组件类型,content provider,不是有intent激活的。当contentResolver发出一个请求时,这种组件就会被激活。因为content resolver直接处理content provider的事务操作,所以组件不需要使用intent,而是直接调用ContentResolver对象的方法。这样在content provider和组件之间留了一层抽象层(为了安全)。
这里分别有一些方法是用来激活其组件的:
- 传递一个Intent对象给
startActivity()
或startActivityForResult()
来启动一个活动 - 传递一个Intent对象给
startService() 来启动一个服务。或者传递一个Intent对象给
bindService() 来绑定一个服务。 - 传递一个Intent对象给
sendBroadcast()
,sendOrderedBroadcast()
, 或者sendStickyBroadcast()来发送一个广播。
- 调用ContentResolver的query()方法在content provider上执行一个查询。
Manifest文件
在系统启动应用程序组件之前,系统必须读取AndroidManifest.xml文件了解有哪些组件存在。这文件位于应用程序的根目录下。
这个文件除了申明应用组件,还可以:
- 制定应用程序所需的用户权限,例如,网络访问或对用户联系人的访问。
- 指定最小的API级别
- 声明软硬件所需的特性,例如:摄像头,蓝牙,多触控屏幕
- 其他库文件,例如,Google Maps library
- 等等
声明组件
声明一个活动的例子如下:
---------------------------------------------------------------------------------------------------------------
<?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>
元素: 活动<service>
元素: 服务<receiver>
元素: 广播接收器
<provider>
元素: 内容提供者
活动,服务,内容提供者没有在manifest文件中声明,即使在程序代码中引用了,还是不能正常运行。然而,广播接受者有两种方式选择,既可以声明在manifest中或者动态创建在代码中(像BroadcastReceiver 对象
),并且调用registerReceiver() 注册在系统中。
声明组件的能力
正如上述,你可以使用Intent来激活活动,服务和广播接收者。在Intent中注明组件的类名,来指定目标组件。然而,在Intent,实际发挥作用的是intent动作action,它可以用来描述你想执行什么样的操作。如果有多个组件可以执行intent动作,用户选择其中一个处理。系统是如何知道哪些组件可以来响应这个intent事件的呢?原来每个应用程序的可以接收响应的 intent事件声明在manifest文件的intent filter中。
声明组件的需求
装载Android系统的硬件设备各种各样,不是所有的设备提供相同的特性和能力。为了阻止你的应用程序不被安装在不支持的设备上,你需要定义应用程序支持的设备能力规格需求说明。系统一般是不关心这些说明的,但是电子市场会读取这些声明来帮助你过滤掉设备不支持的应用程序。
这里有一些在你设计开发时,需要考虑的特性:
-
屏幕尺寸和密度
-
Android为每个设备定义了两种特性:屏幕大小(物理尺寸)和屏幕密度(像素)。
屏幕尺寸: 小, 正常, 大, 超大。
屏幕像素: 低, 中, 高, 超高。一般来讲,你的应用程序兼容所有的屏幕大小和像素。然而,在某些情况,你应该为特定的设备创建特定布局和图片。在manifest文件,
<supports-screens>
可以用来声明支持的屏幕特性。
输入配置
-
许多设备提供各种各样类型的输入机制,例如,键盘,轨迹球,5个方向的导航键。如果你的应用程序需要某种特定的输入硬件,那么你应该在
<uses-configuration>
中指明。然而,这种做法很少见。
设备特性
-
可能你所开发的应用程序所要求的软硬条件在某些Android设备上不支持或不存在,所以不管怎样,你都应该在
<uses-feature>
中声明所有要求的特性。
平台版本
-
Android操作系统有许多不同的版本,例如,Android 1.6 或 Android 2.3, 那么对于程序所开发使用的API级别也有不同。每次新的SDK升级,都会有一些新的API加入。为了你的应用程序所需的API接口在安装设备上可用,你需要在manifest文件中的
<uses-sdk>
声明最小级别的 API Level 是多少。
为你开发的APP声明这些要求是非常重要的,因为,当你发布你的APP在电子市场时,市场平台会帮每个登录的设备过滤出可用的APP。因此,你的应用程序应该只被安装在满足APP所有要求的设备上。
应用程序资源
一个Android程序不只是代码而已, 它还包含图片,音频文件,其他一些与展示有关的东西。例如,在XML文件中定义动画,菜单,风格,颜色,活动的布局。使用分开的资源文件使得不用更改程序代码就可以改变程序的特征。
在Android的工程项目中,SDK构建工具定义了一个唯一的整数ID,你可以在程序代码中或其他一些XML资源文件中引用这个ID。例如,程序中有一个文件名字为logo.png(保存在res/drawable/ 目录下),这个SDK工具会产生一个资源ID名为R.drawable.logo, 你可以用做图片插入到用户接口中。
资源文件与代码分离的最重要的一方面是为不同设备配置提供替代的资源。例如,在XML文件中定义文本时,你能够将这些文本翻译成其他语言并保存在单独的文件中。
根据替代的资源,Android支持许多不同qualifiers。 qualifier被包含在资源目录名中用来定义设备配置。