02 Application Fundamentals–应用程序基本原理

原文链接:http://developer.android.com/guide/components/fundamentals.html

Android应用程序是用Java编程语言写的。Android SDK工具编译你的代码(包含数据和资源文件)到一个后缀名为.apk(Android包)的压缩文件中。一个APK文件包含一个Android应用程序的所有内容,并且是由Android系统驱动的设备用来安装应用程序的文件。

一旦安装到设备上,每一个Android应用生活在它自己的安全沙箱中:

  • Android操作系统是一个多用户的Linux系统,每一个应用程序是一个不通的用户。
  • 默认情况下,系统为每一个应用程序指派一个唯一的Linux用户ID(ID只被系统使用并且对应用程序是透明的)。系统为一个应用程序中的所有文件设置权限,因此只有指派给这个应用程序的用户ID才能访问它们。
  • 每一个进程有它自己的虚拟机(VM),因此一个应用程序的代码在运行时与其他的应用程序是隔绝的。
  • 默认情况下,每一个应用程序在它自己的Linux进程中运行。当这个应用程序中任意一个组件需要被执行的时候Android系统启动这个进程,当它不被需要或者系统必须为其他应用程序回收内存的时候Android系统停止这个进程。
    通过这种方式,Android系统实现了最小特权原则。这就是,每一个应用程序在默认情况下只能访问它正常工作所需的组件。这就创造了一个非常安全的环境,每一个应用程序不能访问未授权的系统部分。

然而,仍然有方法可以将一个应用程序的数据分享给其他的应用程序,并且一个应用程序可以访问系统的服务:

  • 可以安排两个应用程序共享相同的Linux用户ID,这样它们就可以访问另一个的文件。为了节省系统资源,拥有相同用户ID的应用程序可以被安排运行在同一个Linux进程中并且共享相同的VM(应用程序必须用相同的证书签名)。
  • 应用程序可以请求权限来访问设备中的输入,例如:用户的联系人、短消息、SD卡、摄像头、蓝牙等等。所有的应用程序权限必须在安装的时候被用户准许。
    它包含了一个Android应用程序如何在系统中存在的基础只是。这篇文章接下来的部分介绍:

  • 组成应用程序的核心框架组件。

  • 在manifest文件中声明组件和你的应用程序所需的设备特性。
  • 资源文件与应用程序的代码分离,允许你的应用程序方便的为不同配置的设备优化。

App Components
应用程序组件


应用程序组件是一个Android应用程序的必须基础部分。每一个组件是系统可以进入你的应用程序的不同的入口。不是所有的组件对用户来说都是入口一些会依赖其他的,但是每一个都作为它自己的入口存在并扮演一个特定的角色,每一个都是一个唯一的组成模块帮助定义你的应用程序的总体行为。

有四种不通的应用程序组件。每一种都有不同的目的和不同的生命周期定义了组件是如何创建和销毁的:

Activities

一个activity相当于一个包含用户界面的屏幕。例如,一个email应用可以有一个activity来展示邮件列表,另一个activity来撰写email,另一个activity来阅读email。尽管在email应用中这些activities一起工作来提供一个有凝聚力的用户体验,但是每一个都是互相独立的。另外,其他应用可以启动这些activities中的任意一个(如果email应用允许这样)。例如,一个照相机应用可以启动email应用中撰写新邮件的activity以便于用户分享一张照片。

一个activity作为Activity的子类来实现,你可以在Activities中学习更多。

Services

一个service是一个在后台运行的组件,用于执行长时间运行的操作或者为远程进程工作。一个service不提供用户界面。例如,一个service可以在后台播放音乐当用户在使用其他应用的时候,或者它可以在不打断用户和activity交互的时候通过网络获取数据。其他的组件像activity可以启动service并让它运行或者绑定它以便和它交互。

一个service作为Service的子类来实现,你可以在Services中学习更多。

Content providers

content provider负责管理应用程序的共享数据。你可以将数据存储在你的应用程序能访问的位置,如:系统中、SQLite数据库中、网络上、或者其他持久的存储位置。通过content provider其他的应用程序可以查询甚至修改这些数据(如果content provider允许这样)。例如,Android系统提供了一个管理用户联系人信息的content provider。这样拥有合适权限的任一应用程序就可以查询content provider提供的部分数据(例如ContactsContract.Data)以便读取和写入特定联系人的信息。

当读取和写入你的应用程序的私有或者不共享的数据的时候content provider仍然是有用的。例如,Note Pad示例应用使用content provider来保存笔记。

content provider作为ContentProvider的子类来实现并且必须实现一系列标准的API以便其他应用程序可以执行事务。更多信息请查看Content Providers

Broadcast receivers

broadcast receiver是一个响应系统级别广播通知的组件。许多广播起源于系统,例如:在屏幕关闭、电池电量低、照片被捕获的时候都会发送广播。应用程序也可以发送广播,例如:让其他应用知道一些数据已经被下载到设备中并且可以被它们使用。尽管broadcast receivers不会展示一个用户界面,但是它们可以创建一个状态条的通知以此来通知用户广播事件发生。更通俗的说,一个broadcast receiver仅仅是一个连接其他组件的网关并且只执行最小的工作。举个例子,它可以根据事件来初始化一个service来处理工作。

broadcast receiver作为BroadcastReceiver的子类来实现,并且每一个broadcast作为一个Intent对象。了解更多知识,查看BroadcastReceiver类。

任意一个应用程序可以启动另一个应用程序的组件是Android系统一个独特的方面。例如,当你想让用户通过摄像头捕获照片的时候你可以使用其他应用程序已经实现的功能而不是自己开发一个activity来捕获图片。你不需要合并甚至连接到照相机应用程序的代码。替代的,你可以简单的启动照相机应用程序中的activity来捕获一张照片。当拍照完成的时候,照片会返回给你的应用程序并且你可以使用它。对用户来说,照相机就像是你的应用程序的一部分。

当系统启动一个组件的时候,它启动这个应用程序的进程(当应用尚未运行的时候)并且实例化这个组件所需的类。例如,如果你的应用程序启动了照相机应用中的activity来捕获照片,这个activity是运行在照相机应用的进程中,而不是运行在你的应用程序的进程中。因此,不想其他系统中的应用程序,Android系统的应用程序没有一个单一的入口(因为没有main()函数)。

因为系统在一个单独的进程中运行应用程序并且有文件权限来限制访问其他应用程序,你的应用程序不能直接启动其他应用程序中的组件。然后Android系统可以。因此,为了启动其他应用程序中的组件,你必须发送一个消息给系统来具体说明你的intent来启动一个特定的组件。系统之后会为你启动这个组件。

Activating Components
启动组件

四种组件中的三种(activities、services、broadcast receivers)是被一个叫做intent的异步消息来启动的。Intent在运行的时候帮顶特定的组件到其他(你可以想像它们是从其他组件请求一个动作的信使),无论组件是否属于你的应用程序。

intent是Intent对象,它定义了一个启动一个特定组件或者一类特定组件的消息,intent可以是显式或隐式的。

对于activities和services,intent定义了要做的动作(例如,查看或发送一些东西)并可以指定要处理的数据的URI(在这些数据中组件可能需要知道如何开始)。例如,一个intent可能传递一个请求给activity来显示一副图片或者打开一个网页。在某些情况下,你可以启动一个activity来接收请求,在这种情况下,activity也会在Intent中返回结果(例如,你可以分发一个intent让用户选择一个个人的联系人并将它返回给你,返回的intent会包含一个指向所选的联系人的URI)。

对broadcast receivers来说,intent仅仅定义了通告是广播(例如,一个指示电池电量低的广播仅包含了一个已知的action字符串来只是电池电量低)。

另一种组件,content provider,不是被intent启动的。当目标是来自ContentResolver的请求时,它被启动。content resolver处理所有直接和content provider交互的数据,因此组件不需要处理provider的数据而是调用ContentResolver对象的方法。这样在content provider和组件之间的数据请求就存在了一个抽象层(为了安全)。

启动每一种组件的特定的方法:

The Manifest File
Manifest文件


在Android系统可以启动一个应用程序的组件之前,系统必须通过阅读应用程序的AndroidManifest.xml文件(manifest文件)来确认组件是否存在。你的应用程序中的所有组件必须在该文件中定义,并且AndroidManifest.xml文件必须存放在应用程序工程根目录。

manifest文件在添加应用程序的组件声明的时候有很多选项,例如:

  • 指出应用程序说需要的用户权限,例如:网络访问、读取用户联系人信息。
  • 定义应用程序所需的最低API Level
  • 指出应用程序所需的硬件和软件特性,例如:照相机、蓝牙服务、多点触摸屏等。
  • 应用程序所需连接的API库(不是Android框架层API),例如Google Maps library
  • 其他更多

Declaring components
声明组件

manifest文件最重要的任务就是通知系统应用程序有那些组件。例如,在manifest文件中可以这样声明一个activity:

<application>元素中,android:icon属性指向一个用来标识应用程序的图标资源。

<activity>元素中,android:name属性具体说明了Activity子类的类名,android:label属性定义了用户可见的activity的标签。

你必须用以下的方式来声明所有的应用程序组件:

  • <activity>标签用来定义activities
  • <service>标签用来定义services
  • <receiver>标签用来定义broadcast receivers
  • <provider>标签用来定义content providers
    在你的代码中的activities、services、content providers如果不再manifest文件中声明则对系统是不可见的,因此也是无法运行的。然而,broadcast receivers可以在manifest文件中声明也可以在代码中动态声明(作为一个BroadcastReceiver对象)并使用registerReceiver())方法来在系统中注册。

更多的关于如何为你的应用程序构建manifest文件请查看The AndroidManifest.xml File文档。

Declaring component capabilities
声明组件的功能

就像上面的讨论,在启动组件部分,你可以用一个Intent来启动activities、services和broadcast receivers。你可以在intent中明确指出目标组件(使用组件的类名)的名字。然而,intent的真正强大之处在于隐式intent的概念。一个隐式intent仅仅描述要执行的动作的类型并且允许系统查找设备上可以执行这个动作的组件(可以带上要执行的数据)并启动它。如果有多个组件可以执行这个动作,那么让用户选择哪一个来执行。

系统辨认一个组件能否响应intent是通过比较设备上其他应用程序manifest文件中的intent filters是否与接受到的intent匹配。

当你在你的应用中定义了一个activity,你可以选择性的包含定义了这个activity能力的intent filters以便让这个activity可以响应来自其他应用的请求。你可以通过在你的组件中的子标签中增加一个<intent-filter>标签来定义intent filter。

例如,如果你创建了一个带有撰写新邮件activity的email应用,你可以定义一个intent filter来响应发送intent(发送一个新邮件),就像这样:

然后,如果另一个应用程序创建了一个带有ACTION_SEND动作的intent并且通过startActivity()来传递,系统可能会启动你的activity以便用户撰写和发送。

更多的关于创建intent filter的信息请查看Intents and Intent Filters文档。

Declaring app requirements
声明应用程序的要求

有非常多的设备由Android系统驱动,但是它们并非提供都提供一样的特性和功能。为了不让你的应用程序安装在缺少你的应用程序所需特性的设备上,在你的manifest文件中定义一个你的应用程序支持的设备类型的数据通过声明所需的设备和软件是重要的。这些声明大部分只是信息并且系统不会读取它们,但是扩展的服务如Google Play会读取它们为了给用户提供过滤当用户从他们的设备搜索应用的时候。

例如,如果你的应用需要照相机并且使用使用Android 2.1系统,你应当在你的manifest文件中这样声明:

现在如果设备没有照相机并且系统低于Android 2.1将不能从Google Play安装你的应用。

然后,你也可以声明你的应用程序使用照相机但是不需要(require)它。这样,你的应用必须设置required属性的值为false,并且在运行时检查设备是否有照相机并且适当的使照相机不可用。

Device Compatibility文档中你可以查看更多的关于如何管理不同设备中你的应用的功能。

App Resources
应用程序资源


一个Android应用不仅仅是由代码组成的,它需要一些与代码分离的资源文件,例如:图片、音频文件、还有一切与视觉表现相关的文件。例如,你应当定义动画效果、菜单、样式、颜色和由xml文件构成的activity用户界面布局文件。使用应用程序资源文件可以让升级你的应用的版本特性变得容易并且不需要修改代码,并且通过提供一系列可选的资源可以让你为不同配置的设备提供优化(例如,不通的语言和屏幕尺寸)。

在你的Android工程中的每一个资源都由SDK构建工具定义了唯一的整形ID,你可以在你应用的代码中通过这个ID来引用资源或者其他定义在XML中的资源。例如,通过在XML中定义字符串,你可以将字符串转换为其他语言并且将这些字符串保存在分离的文件中。然后,基于一种语言标识符你可以添加资源目录(例如,res/values-fr/来存放法语字符串的值)以及用户的语言设置,Android系统会为你的UI应用合适的语言字符串。

Android系统对你的可选的资源文件支持许多不同标识。标识符是一个短字符串是你包含你的资源目录的名字为了定义不同配置的设备来使用不同的资源。另一个例子,你应当基于设备的屏幕方向和尺寸来为你的不同的activity创建不同的布局文件。例如,当设备的屏幕是竖屏的时候,你可能希望一个有垂直的布局来放置按钮,但是当屏幕是横屏的时候按钮应当水平排列。为了根据不同的屏幕方向来改变布局,你需要定义两种不同的布局文件并且为每一种布局目录应用不同的标识。然后,系统会根据当前设备的方向来自动应用合适的布局。

更多的关于你的应用可以包含的不通类型的资源和如何为不通的设备创建可选的资源请阅读Providing Resources

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">