Application Fundamentals

Android应用程序使用的是Java语言编写。Android SDK工具将代码,数据和资源文件编译进一个Android包,一个以.apk结尾的文件。一个.apk文件被认为是一个应用程序。

一旦被安装到设备上,每个Android应用程序运行在它自己的安全沙箱内。

  • Android操作系统是一个多用户Linux系统,所以每个应用程序都属于不用的用户。
  • 默认的情况下,系统分配给每个应用程序一个唯一的Linux用户ID(这个ID只是给系统使用的,对于应用程序来说是不可知的)
  • 每个process有它自己的虚拟机(VM)。所以每个应用程序的运行是与其它应用程序相隔离的。
  • 默认的情况下,每个应用程序运行在它自己的Linux process中。当一个应用程序的任何一个组件需要被执行的时候,Android就会启动一个process,当这个process不再被需要或者当系统必须从其它应用程序回收内存的时候,Android就会关闭这个process。

这样说来,Android系统实现的是最小特权原则。也就是说,每个应用程序,在默认的情况下 ,访问组件,只能让这个组件来完成你要求的工作,除了这样就不能做更多的事情了。这样就创建了一个非常安全的环境,如果没有给它权限的话 ,一个应用程序就不能访问系统的部件。

(我的理解是:比如你通过Intent来打开某个应用的Activity,你可以在Intent中配置一些参数,让这个应用的Activity来做一些事情,但是你不能做更多的事情了,因为,在你启动别的程序的时候,Android启动了一个新的process,而这个process是运行在自己的虚拟机中,自己的沙箱内,因此保证了安全。)

然而,有多种方式可以让一个应用程序同其他应用程序分享数据,并且让应用程序访问系统服务:

  • 让两个应用程序共享同一个Linux用户ID是可能的,这样,他们就可以分享对方的文件。为了保护系统资源,拥有相同用户ID的应用程序也可以运行在相同Linux process中,并分享相同的VM(应用程序必须拥有相同的签名认证)
  • 一个应用程序可以申请权限来访问设备数据,比如:用户的联系人,短信,sd卡,照相机,蓝牙等等。所有的应用程序权限在程序安装的时候必须被用户准许。

以上覆盖的是基本的关于一个Android应用程序如何存在于Android系统 ,接下来将介绍的是:

  • 完成一个应用程序最核心的framework组件。
  • 为你的程序申明组件和设备特性的manifest文件。
  • 除了程序代码之外的,让你的应用在不同的设备上得到优化的资源文件Resources。

Application Components

Application Components是构建一个Android应用程序必不可少的。每个组件都是一个不同的点,通过这个点,系统可以进入到你的应用程序。对用户而言不是所有的组件都是实际的进入点,一些组件是需要依赖其他组件而存在的,但是每个组件以自己的方式存在,并扮演一个特定的角色,每个组件都是一个唯一的块,帮助你构建你的应用程序的全貌。

(我的理解:对于用户来说,Activity是一个实际的进入点,而Service不是,它们之间在某些情况下相互依赖)

有4种不同类型的应用程序组件,每中类型为截然不同的目的而存在,并有不同的生命周期,这个生命周期控制着组件的创建和销毁。

下面是4种类型的应用程序组件:

Activities

一个activity代表的是一个单独的screen,也就是一个用户接口。例如,一个email应用程序可能有一个activity用来展示一个list的新邮件,另一个activity构成一个email,另一个activity用来读email。虽然这个email应用程序中的这些activities通过良好的用户体验被结合在一起,但是它们之间是相互独立的。就它本身来说,如果这个email程序允许的话,一个其他的应用程序可以启动email程序中的任何一个activity。例如,为了实现照片的分享,一个相机程序可以启动email程序中的activity来构建一封新的邮件。

一个activity是Activity 的子类,你可以通过Activities 的开发指导来学习更多。

Services

一个service是一个允许在后台来执行长时间的操作或者为远程进程remote process执行工作的。service并不提供用户接口。例如,当用户在一个不同的activity中进行操作的同时,一个service可能在后台播放音乐,并且当这个服务从网络上获取数据的时候,也不会对用户当前的activity交互造成任何影响。其他的组件,比如activity,能够启动service,让它允许或者绑定它,让它能够被交互。

一个service是Service 的子类,你可以通过Services 的开发指导来学习更多。

Content providers

一个content provider管理着一个分享的应用程序数据集。你可以在文件系统中存储数据,在SQLite数据库中,在web上,或者其它的你的程序可以访问的存储介质上。通过content provider,其它的应用程序可以查询甚至修改数据(如果content provider运行的话)。例如,Android系统提供了一个content provider来管理用户的联系人信息。就本身来说,任何应用程序,只用拥有了适当的权限都能够通过content provider(比如:ContactsContract.Data )来针对特定的人员读写个人信息。

Content Providers对于你的应用程序的私有数据的读写也很有帮助。例如sample application Note Pad 就是使用content provider来保存数据的。

content provider是ContentProvider 的子类,并且必须实现一个标准的API集使得应用程序可以执行事务。如果需要更多的信息,查看开发指导Content Providers .

Broadcast receivers

一个broadcast receiver是一个能够响应系统级别的广播通知。许多的broadcast来自系统,例如,当屏幕关闭的时候,电池电量低的时候,或者照片拍下以后,都会有一个broadcast发出。应用程序也可以发出广播,比如,让其他的应用程序知道某些数据已经被下载到设备上了,并且可以供他们使用。尽管broadcast receivers不显示一个用户接口,它们可以在状态栏上面创建一个通知notification来告诉用户一个broadcast事件发生了。更通常的说,尽管一个broadcast receiver对其它组件来说只是一个关口“gateway”,并且被用来做很少的工作量。例如,可以使用它,基于某种事件来初始化一个服务来执行一些工作。

broadcast receiver是BroadcastReceiver的子类,并且每个broadcast被作为一个Intent对象进行分发。需要更多信息,可以参考BroadcastReceiver 类。

Android系统中独特的一个设计特点是:任何应用程序可以启动其他应用程序的组件。例如,如果你想让用户使用设备进行拍照,很可能别的应用程序已经实现了,所以你可以直接使用,而不是自己去开发一个带有照相功能的activity。对此,你不需要合并或者链接你的代码到实现照相功能的应用程序。而是,你可以很简单地启动照相应用程序中的带有照相功能的activity。当完成的时候,照片甚至可以返回给你的应用程序,你就可以使用它了。对用户来说,似乎相机是你的程序的一部分。

当系统启动一个组件,它为该应用程序启动一个process(如果该程序还没有运行的话),并且实例化这个组件所需要的类。例如,如果在你的应用程序启动照相应用程序的带有照相功能的activity来照相,那么这个带有照相功能的activity所在的process是属于照相应用程序的,而不是在你的应用程序的process。因此,不像大部分的其他的系统中的应用程序,Android应用程序不存在一个单独进入点(比如,不存在main()这个函数)。

由于系统在不同的process中运行每个程序,并通过文件权限来限制对别的应用程序的访问,你的应用程序不能直接激活其他应用程序的组件。然而,Android系统可以,因此,为了激活其他应用程序的组件,你必须给系统发送一个消息指定你的意图来启动特定的组件。通过系统来为你激活组件。

Activating Components

4种组件中的3种--activities,services,broadcast receivers--是通过一种叫做intent的异步消息激活的。Intents在运行时绑定独立的组件,无论这些被绑定的组件是属于你的应用程序还是其他的应用程序。(你可以把这些intents想象成信使,从其它应用程序中请求一个action)。

一个intent被Intent 对象所创建,它定义了一个消息,这个消息用来激活特定的组件,或者指定类型的组件--一个intent可以是详细具体的的或者不详细的,某一类型的。

对于activities和services,一个intent定义action来执行(例如,类似“view”或者“send”之类的东西),并可以指定,数据的URI,来执行(其中包括了这个组件被启动的时候所需要知道的东西)。例如,一个intent可能代表了一个展示一张图片或打开web页面的请求。在一些情况下,你可以启动一个activity来接收结果,在这种情况下,这个activity也通过Intent来返回结果(例如,你可以发出一个intent,让用户选择一个联系人,并让它返回数据给你--那个返回的intent就包含了一个指向被你选中的联系人的URI)。

对于broadcast receiver,intent简单定义了要被广播的通知(例如,一个用来标识设备电池低的broadcast只包含了一个已知的字符串“battery is low”)。

另外一个组件content provider,不是通过intent激活的,它是被来自ContentResolver 的一个请求当做目标的时候激活的。The content resolver handles all direct transactions with the content provider so that the component that's performing transactions with the provider doesn't need to and instead calls methods on the ContentResolver object. This leaves a layer of abstraction between the content provider and the component requesting information (for security).(这里不太好理解,直接贴出来

有不同的方法来激活不同类型的组件:

  • 你可以启动一个activity(或者给它一些新的事情做),通过传递一个Intent给startActivity() 或者startActivityForResult() (当你想让该activity返回结果)。
  • 你可以启动一个服务(或者给正在运行的服务一个新的指令),通过传递一个Intent给startService() 。或者你可以通过传递一个Intent给bindService() 来绑定服务。
  • 你可以构建一个broadcast通过传递一个Intent给方法sendBroadcast() ,sendOrderdBroadcast() ,或sendStickyBroadcast()
  • 你可以在一个ContentResolver上调用query() 方法来查询一个content provider

获取更多的关于使用intents的信息,参考Intents and Intent Filters 文档。更多信息关于激活特定的组件在下面的文档中提供:Activities Services BroadcastReceiver Content Providers

The Manifest File

在Android系统能够启动一个应用程序组件之前,系统必须通过读取应用程序的AndroidManifest.xml文件(manifest文件)来获知存在的组件。有的应用程序必须在这个文件中申明它所有的组件。这个文件必须存在于程序的根目录下。

manifest文件除了申明应用程序的组件外还做了许多事情:

  • 识别应用程序中请求的所有的权限,例如网络访问或者读取访问用户的联系人。
  • 申明应用程序要求的最小的API Level ,即应用程序能基于的最小的API版本。
  • 申明应用程序中使用或请求的硬件和软件特点,比如相机,蓝牙,服务或者屏幕的多点触摸。
  • 申明应用程序中使用到的非Android framework APIs中的库,例如,Google Maps library
  • 其它更多

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上指定一个用户可见的label字符串。

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

<activity>元素针对的是activities

<service>元素针对的是services

<receiver>元素针对的是broadcast receiver

<provider>元素针对的是content provider

源码中的activities,services,和content provider如果没有在manifest文件中申明,那么对系统是不可见的,因此,永远不会运行。然而,broadcast receivers既可以在manifest中申明,也可以通过代码动态地创建(以BroadcastReceiver 对象),并通过调用registerReceiver() 来向系统注册。

想知道更多关于你的应用程序的manifest文件的信息,参考The AndroidManifest.xml File 文档。

Declaring component capabilities

正如上面所讨论的Activating Component中,你可以使用Intent来启动activities,services和broadcast receiver。你可以在intent中指定目标组件(通过组件的名称)。然而,intent真正强大的地方在于intent actions。通过intent actions,你只要简单地描述你想要执行action的类型(和可选的,用来执行这个action的数据),并允许系统去设备上查找可以执行这个action的组件,并启动它。如果有多个组件可以执行这个intent描述的action,那么用户就可以选择使用哪一个。

系统识别哪个组件可以响应intent的方式是通过将接收到的intent和设备中的其他应用程序的manifest文件中提供的intent filter相比较。

当你在你的应用程序的manifest文件中申明一个组件,你可以任意包含intent filters,用来标识这个组件的能力。这样它就可以响应来自其它应用程序的intents。你可以在你的组件中添加一个<intent-filter>子标签元素来申明一个intent filter。

例如,一个email应用程序,它包含一个组成新邮件的activity,那么就可以在它的manifest文件中申明一个intent filter用来响应“send”intents(为了发送邮件)。你的应用程序中的一个activity可以创建一个包含“send”action(ACTION_SEND)的intent,这样当你调用startActivity()的时候,系统就会去匹配email应用程序中的“send”activity,并启动它。

更多关于创建intent filters的信息,参考Intents and Intent Filter 文档。

Declaring application requirements

有许多不同的Android设备,并不是所有都拥有相同的规格和特性。为了防止你的应用程序被安装在缺乏你的应用程序所需要的特性,在manifest文件中清晰地定义一个描述你的应用程序所支持的软硬件类型的文件就显得很重要了。大部分这些声明只是信息而已,系统不会去读取它们,但是,外部服务,例如Google Play会去读取它们,为的是让用户搜索适合它们设备的应用程序提供一个过滤。

例如:如果你的应用程序要求使用照相功能,并且使用的是Android2.1的API,你应该在你的manifest文件中申明这些要求。这样的话,没有照相机和Android版本低于2.1的设备就不能从Google Paly上安装你的应用程序。

然而,你也可以申明你的应用程序使用照相机,但是不是必须的。这种情况下,你的应用程序必须进行运行时检查来决定设备是否有照相机并让相机功能有关的特性不可用。

下面是一些重要的你设计和开发应用程序应该考虑的设备规格参数:

Screen size and density

为了根据屏幕类型对设备进行分类,Android为每个设备定义了两种规格参数:屏幕size(屏幕的物理尺寸physical dimension)和屏幕density(屏幕的物理密度像素,dpi,dots per inch)。为了简化所有不同类型的屏幕,Android系统将它们进行了归类,以便更容易进行定位。

屏幕size:  small,normal,large,extra large.

屏幕densities:  low,medium,high,extra high.

默认地,你的应用程序兼容所有的屏幕size和屏幕density,因为Android系统能够自适应你的UI布局和图片资源。然而,你应该为确定的屏幕size提供指定的布局和为确定的屏幕density提供特定的图片。使用可以替代的布局文件,并且在你的manifest文件的<supports-screens>元素中申明你的应用程序所支持的屏幕类型。

更多信息参考Supporting Multiple Screens 文档。

Input configurations

许多用户提供了一个不同类型的输入装置,比如一个物理键盘,一个滚球,或者一个5个方向的导航键盘。如果你的应用程序要求一个特定类型的输入硬件,你应该在你的应用程序的manifest的<uses-configuration>元素中申明。然而,一个应用程序需要一个特殊的输入方式是很少见的。

Device features

有许多硬件和软件特点可能存在或不存在于一些Android设备中,比如照相机,传感器,蓝牙,某个版本的OpenGL,或者触摸屏幕的精度。你应该假设这些特定在某些机器上是不可用的(除非你使用的是标准的Android库),因此你应该使用<uses-feature>标签来申明你的应用程序特点。

Platform Version

不同的Android设备经常运行在不同版本的Android平台上,例如Android1.6或者Android2.3.每个相继的版本相对于前版本通常加入了新的APIs。为了标识哪些APIs集是可用的,每个平台版本指定一个API Level(例如:Android1.0是API Level 1,Android2.3是API Level9)。如果你使用1.0版本后的APIs,你应该使用<uses-sdk>标签申明最小的API Level。

为你的应用程序声明这些要求非常重要,因为当你提交你的应用程序到Google Play,Google商店会根据这些声明来过滤哪些设备可以使用这个应用程序,只有所有要求都符合的时候,你的应用程序才可用。

更多关于Google Play如何基于这些或其他要求来过滤应用程序,请参见Filter on Google Play 文档。

Application Resources

一个Android应用程序不仅仅是由代码构成的--除了代码之外,它还要求特定的资源文件,例如图片,声音和其它与应用程序视觉显示相关的东西。例如,你应该定义动画,菜单,样式,颜色,和activity相关的布局文件。使用应用程序资源可以很容易地更新你应用程序的规格而不需要修改代码--提供可替换的资源文件,是的你的的应用程序在不同的设备上都可以适应各种不同的设备(例如不同的语言和屏幕大小)。

SDK build 工具为你的Android项目中的每个资源定义一个唯一的整型ID,你可以通过这个值在你的代码或者XML中定义的其它资源文件中来引用它。例如,如果你的应用程序包含一张名为logo.png的图片(保存在res/drawable/directory)。SDK工具生成一个资源ID,名为R.drawable.logo,你可以用来关联图片,并将它插入你的用户接口。

将资源文件和你的源码区分开来的最重要的方面是让你能提供可替换的资源文件,以适应不同的设备。例如,在XML中定义UI字符串,你可以将文字翻译成其他语言并将它们保存到不同的文件中。你可以根据用户的语言设置在资源目录追加资源目录名(例如,针对法语,建立文件夹res/values-fr),Android系统会为你的UI引用不同的语言。

为你的可替换资源,Android支持许多不同的修饰语支持。修饰语是一个短的字符串,使用这个修饰语作为资源文件的目录的名称,这样的目的是你的设备可以适应不同的设备。举个例子,根据屏幕的方向和大小,你通常需要为你的activity创建不同的布局。例如:当设备的屏幕是竖屏,你可能想要一个垂直摆放按钮的布局,当屏幕是横着摆放的时候,你可能想让你的按钮水平摆放。你可以定义两种不同的布局来适应这两种情况,并为它们起适当的名字,这样系统就能够针对不同的屏幕方向自动适应布局。

更多的关于你的应用程序中能够包含哪些不同类型的资源,以便让你的程序适应各种不同设备,参考Application Resources 开发指导。

本文链接:http://developer.android.com/guide/components/fundamentals.html#Resources

猜你喜欢

转载自michaelye1988.iteye.com/blog/1755221