当前位置: 代码迷 >> Android >> 【译】Android开发指南(二)-应用程序基础
  详细解决方案

【译】Android开发指南(二)-应用程序基础

热度:93   发布时间:2016-05-01 18:55:02.0
【译】Android开发指南(2)--应用程序基础

本博文乃原创翻译,欢迎转载,转载时请注明博客作者,谢谢:-)

http://simlelin.iteye.com/admin/blogs/1168877

?

Application Fundamentals
应用程序基础组件


概要

  • ??? Android应用程序由一个或更多的应用程序组件(活动,服务,内容提供者和广播接收者)组成

?

  • ??? 每一个组件在整个应用程序行为中担任一个不同的角色,并且每一个组件能被独立地激活(甚至是被其它的应用程序)

?

  • ??? Manifest文件必须声明应用程序中的所有的组件,并且应该声明所有的应用程序的要求,如所需要的Android的最低版本号和任意的硬件配置的要求

?

  • ??? 非代码形式的应用程序资源(图片,字符串,布局文件等等)应当针对不同的硬件配置有不同的选择(如针对不同的语言提供不同的字符串,针对不同的屏幕大小设计不同的页面布局)


Android应用程序由Java编程语言所写。Android SDK工具将代码(包括数据和资源文件)编译到一个Android的打包文件中,即一个后缀为.apk的文件。所有的在一个.apk文件中的代码被认为是一个应用程序,供Android设备安装应用程序。

一旦被安装到一台设备上,每一个Android应用程序便独立存在与自己的沙盒中:

  • ??? Android操作系统是一个多用户的Linux系统,每一个应用程序是一个不同的用户。

?

  • ??? 默认地,系统分配给每一个应用程序一个独一无二的Linux用户ID(此ID仅被操作系统使用并且对于应用程序来说是未知的)。操作系统给一个应用程序针对所有的文件设置许可,以便那个仅有的用户ID的应用程序可以访问它们。

?

  • ??? 每一个进程拥有它自己的虚拟机,因此一个应用程序的运行是独立与其它的应用程序的。

?

  • ??? 默认地,每一个应用程序运行于它所属的Linux进程。Android在该应用程序的任何一个组件需要被执行的时候启动这个进程,在这个进程不再被需要的时候或者是操作系统必须重这个应用程序中回收内存的时候关闭这个进程。

这样,Android系统实现了最小权限的规则。即,每一个应用程序,在默认地时候,只有组件为了完成它的工作所必须的访问权限而不会有更多的权限了。这样就创造了一种非常安全的环境,应用程序不能访问系统没有给予许可的地方。

尽管如此,仍然有许多方法可供应用程序同其它的应用程序共享数据,可让应用程序访问到系统的服务:

  • ??? 让两个不同的应用程序共享同一个Linux用户ID是可能的,这样它们就可以互相访问彼此的文件。为了节省系统资源,有相同用户ID的应用程序也可以在同一个Linux进程下运行,共享同一个虚拟机(前提是应用程序必须有相同的签名认证)。

?

  • ??? 一个应用程序可以请求许可以访问设备数据诸如用户的联系人,短消息,SD卡,照相机,蓝牙设备等等。所有的应用许可必须在程序安装的时候由用户给予授权。


以上含扩了关于一个应用程序是如何存在与系统中的基本知识。此文当的余下部分将要向你介绍:

  • ??? 定义你的应用程序的核心框架组件。
  • ??? 声明组件和应用程序需求的manifest文件
  • ??? 从代码中分离并且允许你的应用程序在不同的设备配置下做优雅的优化的资源文件。

应用程序组件


应用程序组件是一个Android应用程序所必须的构建单元。每一个组件是系统能进入你的应用程序的不同的入口点。对用户来说不是所有的组件都是事实上的入口点,有一些组件互相依赖,但是每一个组件都有它自己的入口点并且扮演着特殊的角色--每一个组件是一个独特的构造块,帮组定义你的应用程序的整体的行为。


有四种不同类型的应用程序组件。每一种类型作用于不同的目的,并且拥有不同的生命周期,定义了组件如何创造和销毁。

如下便是这四种应用程序组件的介绍:

?

activity

活动

??? 一个activity有一个单屏呈现的用户界面。例如,一个email应用程序可能有一个activity用来显示一列新邮件,有另一个activity来写一封email,有另一个activity来读邮件。尽管这些activities协同工作在email应用程序表现出了一致的用户体验,它们中的每一个都是相互独立的。所以,一个不同的应用程序可以启动这些activities中的任何一个(如果email应用程序允许这一点)。比如,一个照相程序可以启动email应用程序中的写email的activity以让用户分享一张照片。

??? 一个activity以Acitivity的子类的形式实现,更多的activity的内容可以查看Activities开发指南。

Services
服务


??? 一个service组件可以运行于后台来进行长期的操作,或者是完成远程的工作。service是没有用户界面的。比如,一个service可以在用户在执行另外一个应用程序的时候运行于后台播放音乐,或者是接收网络数据不至于中断用户与当前activity的交互。另外一个组件,如一个activity,可以启动一个service并让它运行,或者是对它进行绑定以和它进行交互。

??? 一个service以Service子类的形式实现,更多的service内容可以查看Services开发指南。

Content providers
内容提供器


??? 一个内容提供器管理共享的应用程序数据。你能通过文件系统、SQLite数据库、网络或者任何其它的你应用程序可以访问的持久化存储来存储数据。通过内容提供器,其它的应用程序可以查询甚至修改数据(如果内容存储器允许)。例如,Android系统提供一个管理用户联系人的内容提供器。这样,任何应用程序在合适的许可下就可以访问该内容提供器的一部分(如ContactsContract.Data)来读写特定的某人的信息。

??? 内容提供器也同样可以用于读写你应用程序的私密数据而不去共享。例如,记事本例子程序使用一个内容提供器来存储记录。

??? 一个内容提供器以ContentProvider的子类形式来实现,且必须实现一套标准的API来执行事物。更多的信息可以查看Content Providers开发指南。

Broadcast receivers
广播接收器


??? 一个广播接收器是一种可以对系统范围内的广播内容进行相应的组件。许多广播始于系统-例如,一个广播通知屏幕灭掉了,电池电量低或者一张图片被截取了。应用程序也可以初始化广播-例如,让别的应用程序知晓有数据被下载到设备中可被其它它们使用。尽管广播接收器不显示用户界面,当一个广播时间发生时它们可以创造一个状态条通知来提醒用户。更常见的,一个广播接收器对于其它组件来说仅仅是一个网关,被用来做非常少量的工作。例如,它能够初始化一个服务来执行基于该事件的工作。

??? 一个广播接收器以BroadcastReceiver的子类形式来实现,每一个广播被封装在一个Intent对象中传递。更多的信息,可以查看BroadcastReceiver类。

Android系统设计的一个独特的方面是任何应用程序可以启动另外一个应用程序的组件。例如,如果你想要用户用照相设备拍照,可能有另一个应用程序有这个功能而你的应用程序可以使用它,而不必自己再去开发一个实现照相功能的activity。你不需要合并或者甚至链接至照相程序的代码。你仅仅需要启动照相程序的activity来照相即可。当照完相了,照片甚至会被返回给你的应用程序这样你可以直接使用照片了。对于用户来讲,这看起来像是照相功能就是你应用程序的一部分。

当系统启动一个组件时,它会启动该程序的进程(如果该程序还没有被运行)并且实例化该组件所需要的类。例如,如果你的应用程序启动了照相程序中的拍照功能的activity,该activity运行于属于照相程序的进程,而不是你应用程序的进程。因此,不像大多数其它系统中的应用程序,Android应用程序不需要一个唯一的入口点(例如没有main()函数)。

因为系统在各自独立的进程中运行每一个应用程序,每一个进程的文件许可对于其它应用程序是严格限制访问的,你的应用程序不能直接激活来自另一个应用程序的组件,但是Android系统可以。所以,要激活另一个应用程序中的一个组件,你必须给系统传递一个描述你启动一个特定组件意图的消息,然后系统替你激活组件。

Activating Components
激活组件


四组件中的其三-activities, services和broadcast receivers-通过由intent调用的异步消息来激活。Intent在运行时绑定到独立的组件上(你可以将它们想象成向其它组件请求行为的信使),不在乎组件是属于你的应用程序还是别人的。
An intent is created with an Intent object, which defines a message to activate either a specific component or a specific type of component—an intent can be either explicit or implicit, respectively.
一个intent以一个Intent对象的形式创建,它定义了激活一个特定组件或者一个特定类型组件的消息(一个intent可以是显式的,也可以是隐式的)。

对于activities和services,一个intent定义了将要执行的动作(例如,去看或者是发送某物)并可以指定采取行动的数据的URI(组件在启动的时刻需要知道的信息)。例如,一个intent可能要传递一个显示一张图片或打开一个web页面的请求。在一些情况下,你可以启动一个activity来接收结果,在这种情况下,此activity也会在一个Intent中返回结果(例如,你可以通过一个intent让用户选择一个个人的通讯录并把它返回给你-该返回的intent包括一个指向所选的联系人的URI)。

对于broadcast receivers,intent仅仅定义了正在被广播的声明(例如,一个指示设备电池电量低的广播仅包含一个特定的字符串以指示“电池电量低”)。

最后的一个组件类型,content provider,不会被intent激活。事实上,它当被ContentResolver发出请求的时候被激活。content resolver处理所有content provider的事务,因此处理privider提供事务的组件是不需要的,取而代之的是ContentResolver对象的方法调用。如此便在content provider和请求信息的组件之间形成了一个抽象层(为了安全)。

以下是每种组件激活的方法:

  • ??? 你可以通过传递一个Intent给startActivity()或startActivityForResult()(当你想要activity返回一个结果时)方法来启动一个activity(或是给它传递一些新的东西)。
  • ??? 你可以通过传递一个Intent给startService()来启动一个服务(或者是给正在运行的服务新的指令)。或者你可以通过传递一个Intent给bindService()来绑定到服务
  • ??? 你可以通过传递一个Intent给像sendBroadcast()、sendOrderBroadcast()或sendStickBroadcast()这样的方法来初始化一个广播。
  • ??? 你可以调用一个ContentResolver对象的query()方法对一个content provider进行查询。


更多的使用intent的信息,请查看Intents和Intent Filters的文档。更多的关于激活特定种类组件的信息在如下文档中提供:Activities,Services,BroadcastReceiver和Content Providers。

The Manifest File
Manifest文件


在Android系统能够启动一个行用程序组件之前,系统必须通过读应用程序的AndroidManifest.xml文件来知道组件的存在。你的应用程序必须在此文件中声明所有用到的组件,此文件必须处于应用程序工程路径的根目录下。

manifest文件除了声明应用程序组件之外还做了如下几件事情:

  • ??? 鉴别应用程序请求的所有的用户许可,如Internet访问许可或用户联系人的读权限许可。
  • ??? 声明应用程序请求的最小的API级别,基于此级别应用程序使用相对应的API。
  • ??? 声明应用程序使用或请求的硬件和软件特性,例如照相机,蓝牙服务或多点触摸屏。
  • ??? 应用程序需要链接的API库(在Android框架API之外),如Google地图库。
  • ??? 以及更多


Declaring components
声明组件


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属性指向标识应用程序的图标资源。

在<activity>单元中,android:name属性指定了Activity子类的全名,android:label属性指定了activity的用户可见标签所用到的字符串。


你必须像这样来声明所有的应用程序组件:
??? <activity> elements for activities
??? <service> elements for services
??? <receiver> elements for broadcast receivers
??? <provider> elements for content providers

你应用程序的代码中包含但是没有在manifest文件中声明的所有activity,service和content provider对于系统是不可见的,并且后果是永远不会被运行起来。然而,broadcast receiver可以既不用在manifest文件中声明也不必在代码中动态的创建(作为BroadcastReceiver对象)就可以通过调用registerReceiver()方法在系统中进行注册。

更多的关于你应用程序manifest文件的构成,请参考AndroidManifest.xml文件文档。

Declaring component capabilities
声明组件的能力


如之前讨论的,要激活组件,你可以使用一个Intent来启动activity,service和broadcast receiver。你可以通过在一个intent中明确命名目标组件(使用组件的类名)来做到。然后,intent真正的威力在于intent action的概念。通过intent action,你仅仅只需要描述你想要执行的行动的类型(也可以是基于你想要执行行动的数据),然后让系统在设备上找到一个可以执行此行动的一个组件并且启动它。如果有多个组件符合用户在intent中的描述,就让用户选择一个来使用。

系统识别一个组件所能响应的intent的方法是通过将接收到的intent和设备上其它应用程序提供的manifest文件中声明的intent filter进行比较(通过了过滤器的即为可供选择的组件)

当你在你的应用程序的manifest文件中声明了一个组件后,你可以在组件后面添加一个intent filter来声明该组件的能力,这样它就可以响应来自其它应用程序的intent了。你可以通过在组件声明单元下面添加一个<intent-filter>的子单元来给你的组件声明一个intent filter。


例如,一个email应用程序有一个activity供撰写新的邮件就可能在程序的manifest文件中声明了一个intent filter来响应"send"的intent(以发送email)。你应用程序中的某一个activity可以创建一个带有"send"动作(ACTION_SEND)的intent,系统会匹配email应用程序中的"send"的activity并且当你在通过startActivity()方法来唤醒intent时启动它。

关于创建intent filter的更多的信息,请参见Intent和Intent Filter文档。

Declaring application requirements
声明应用程序的需求


有许多运行Android的设备,并不是所有的设备拥有相同的性能和功能。为了防止你的应用程序被运行在没有你应用程序所要求的能力的设备上,给能满足你应用程序manifest文件中声明的所需要的设备和软件需求的设备清晰的定义一个设备类型清单是很重要的。这些声明大多数是象征性的,系统并不一定会去读它,但是外部服务诸如Android时称读取它们,可以在用户为他们的设备搜索应用程序的时候提供过滤功能。

例如,如果你的应用程序需要一个摄像头,并且使用Android 2.1版本的API(API等级7),你就应该在你的manifest文件中声明出来。这样,没有摄像头或Android版本低于2.1的设备就不能从Android市场安装你的应用程序。

然而,你也可以在你的应用程序中声明需要使用摄像头,但并不会真的用到。这种情况下,你的应用程序必须在运行时执行检查,判断该设备有没有摄像头,如果摄像头不可用,就关闭程序中需要使用摄像头的特性。

以下这些重要的设备特征,在你设计和开发应用程序的时候需要考虑到:

屏幕大小和分辨率

为了通过屏幕类型给设备分类,Android给每一个设备定义了两个特征:屏幕大小(屏幕的物理尺寸)和屏幕分辨率(屏幕上的物理像素密度或者每英寸的点数)。为了简化所有种类屏幕的配置,Android系统将它们归纳如选定组以让它们更容易被分类出来。

  • ??? 屏幕的大小分为:小型,普通型,大型和超大型。

?

  • ??? 屏幕分辨率分为:低分辨率,中分辨率,高分辨率和极高分辨率。


??? 默认下,你的应用程序是兼容所有种类的屏幕大小和分辨率大小的,因为Android系统会对你的UI布局和图像资源进行合适的调整。但是,你应该为特定大小的屏幕创建特定的布局,为特定的分辨率屏幕提供专门的图像,使用可选的布局资源,在你的manifest文件中用<supports-screens>单元明确地声明你的应用程序支持哪些种类的屏幕大小。

??? 更多的信息,请参考Supporting Multiple Screens文档。

输入配置

??? 许多设备提供不同类型的用户输入机制,如硬件键盘,轨迹球或者是五向导航键。如果你的应用程序需要一个特定种类的输入硬件,你应该在manifest文件中用<uses-configuration>单元进行声明。然而,很少有应用程序需要一种特定的输入配置。

Device features
设备特性


??? 有许多硬件和软件特性可能存在也可能不存在于一个Android设备中,例如摄像头,光传感器,蓝牙设备,特定版本的OpenGL,或者是触摸屏的保真度。你永远不应该假定一种特性在所有的Android设备上可用(不包括Android标准库的功能),因此你使用<uses-feature>单元来声明你的应用程序要用到的特性。

Platform Version
平台版本

??
??? 不同的Android设备经常运行不同的版本的Android平台,如Android 1.6或Android 2.3。每一个新版本常常包含不被上一版本所支持的额外的API。为了指明API是哪一个版本的,每一个平台版本都有一个API等级(例如,Android 1.0的API级别是1,Android 2.3的API级别是9)。如果你用到了任意的晚于1.0版本的API,你应用使用<uses-sdk>单元声明最低要求的API级别。

为你的应用程序声明所有的需求是很重要的,因为,当你将你的应用程序发布到Android市场,使用会根据这些声明来过滤对于每一台设备哪些应用程序是可用的。如此,你的应用程序仅仅只是对满足你应用程序能力需求的设备可用。

更多的关于Android市场如何基于能力需求过滤应用程序的信息,请参考Market Filters文档。

Application Resources
应用程序资源


一个Android应用程序不仅仅由代码组成-它还需要代码之外的资源,诸如图像,音频文件和与应用程序可视化呈现相关的任何东西。例如,你应该使用xml文件定义动画,菜单,样式,颜色和activity的用户界面布局。使用应用程序资源会使得不改动代码而更新你应用程序不同的地方变得更容易-通过多套可选的资源-使得你可以针对不同的设备配置来优化你的应用程序(如不同的语言和屏幕大小)。

对于每一个引入你Android工程的资源,SDK构建工具会定义一个独一无二的整型ID,你可以用它来引用你代码中的资源或来自定义于xml文件中的其它资源。例如,如果你的应用程序包含一张叫logo.png的图片(保存在res/drawable目录下),SDK工具会生成一个资源ID叫做R.drawable.logo,你可以用它来引用这张图片,将图片插入到你的用户界面中。

将提供的资源从源代码中分开的最重要的一个方面是你拥有为不同的硬件配置文件提供不同的资源的能力。例如,通过在xml文件中定义UI字符串,你可以将这些字符串翻译成其它的语言,并将这些字符串保存到不同的文件中。然后,通过你资源文件目录后缀的语言限定(如res/values-fr/表示法语的字符串)和用户的语言设定,Android系统会给你的UI使用合适的语言。

Android为你的不同的资源提供多种的限定符的支持。限定副是一个包含在你的资源目录名字中的短字符串,根据设备的配置文件来决定使用哪种资源。作为另一个例子,你常常会为你的activity创建不同的布局,这些布局取决于设备屏幕的方向和大小。如,当设备屏幕是竖着的方向,你会想要一种按钮是垂直排列的布局,但是当你的屏幕是横着的时候,按钮就应该被水平排列。为了做到根据屏幕方向来改变布局,你可以定义两套布局,并对每个布局的目录名使用不同的限定符。这样,系统就会根据当前设备的方向自动的采用合适的布局。

更多的关于应用程序中包含的不同种类的资源和如何针对不同的设备配置文件创建可选的资源,请参考应用程序资源的开发手册。

  相关解决方案