Application Fundamentals(应用基础)

来源:互联网 发布:uml 数据库建模 编辑:程序博客网 时间:2024/05/29 11:44

文章转载禁止用于商业用途,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处莫高雷草原以及作者@JiongBull。

访问Android API指南目录索引查看全部翻译

应用基础

Android应用是用Java编程语言编写的。Android SDK工具会把你的代码连同其他数据和资源文件一起编译到APK(Android package,一种后缀带有.apk的打包文件)中。
APK文件中包含了Android应用的全部内容,Android设备就是使用它来安装应用的。

一旦被安装在设备上,每个Android应用都运行在它们自己的安全沙箱中:

  • Android操作系统是一种基于Linux的多用户操作系统,每种应用都对应一个用户。
  • 默认情况下,系统会为每个应用分配一个唯一的Linux用户ID(这个ID仅被系统使用,对于应用来说是未知的)。系统会为应用中的所有文件设置权限,这样只有分配给该应用的用户ID可以访问它们。
  • 每个进程都有它们自己的虚拟机(VM),所以应用的代码可以隔离开其他应用独立运行。
  • 默认情况下,每个应用运行在它自己的Linux进程中。当应用中的任何组件需要被执行时,Android就会启动这个进程,而当不需要或者系统必须为其他应用回收内存时,就会关闭这个进程。

这样,Android系统就落实了最低权限原则。也就是说,每个应用默认只对它需要用来完成工作的组件拥有访问权限,仅此而已。这就创造了一个非常安全的环境,因为应用无法访问没有授权给它的系统的其他部分。

然而,应用也是有办法和其他应用共享数据甚至访问系统服务的:

  • 两个应用共享同样的Linux用户ID是可能的,这样它们就可以互相访问彼此的文件了。为了节省系统资源,拥有相同用户ID的应用也可以运行在相同的Linux进程中并且共享同一个VM(这些应用必须用相同的证书来签名)。
  • 应用可以请求访问设备数据的权限,例如用户的联系人、短信、装载的存储器(SD卡),摄像头、蓝牙等等。所有的应用权限都必须在安装时得到用户的授权。

上面涵盖了关于Android应用如何在系统中执行的基础知识。这篇文档的余下部分将会向你介绍:

  • 定义应用的核心框架组件。
  • 在manifest文件中为你的应用声明用到的组件和需要的设备特征。
  • 资源是和应用的代码分离开的,能让你的应用优雅的为多种设备的配置进行性能优化。

应用组件


应用组件是Android应用的基础构件。每个组件都是系统进入你应用的一个与众不同的入口。尽管并不是所有的组件都是用户的实际切入点,而且有些甚至是互相依赖的,但是每个组件都有自己的实体并扮演着一些特殊的角色(每一个组件都是定义你应用总体行为的独一无二的构件)。

总共有四种不同类型的应用组件。每种类型都有明确的使用目的,并且明确定义了决定组件如何创建和销毁的生命周期。

下面是四种类型的应用组件:

Activity
activity代表用户界面中的一个单独的屏幕。例如,一个邮件应用可能有一个用来显示新的邮件列表的activity,另一个activity来写邮件,还有一个activity来阅读邮件。尽管在这个邮件应用中的所有activity一起凝聚成了一个完整用户体验,但是它们之间都是独立的。照此,其他的应用可以启动该应用中的任何一个activity(如果邮件应用允许的话)。例如,相机应用可以启动邮件应用中的activity来编写新邮件来分享照片。

通过继承Activity来实现activity,你可以阅读Activity开发指南来了解更多信息。

Service
service是在后台中运行的用来执行费时操作或远程操作的组件。service并不提供用户界面。例如,service可以在用户运行另外的应用时在后台播放音乐,或者在不阻塞用户与activity的交互时通过网络获取数据。其他的组件,例如activity,可以开启并运行service或绑定service与之交互。

通过继承Service来实现service,你可以阅读Service开发指南来了解更多信息。

Content provider
content provider用来管理共享的应用的数据集。你可以把数据存储在文件系统中、SQLite数据库中、web上或其他任何你的应用可以访问到的永久存储器中。其他的应用可以通过content provider来查询甚至修改这些数据(如果content provider允许的话)。例如,Android系统提供了管理用户联系人信息的content provider。照此,任何拥有适当权限的应用都可以查询content provider(例如ContactsContract.Data)的某些部分来读写某个联系人的信息。

content provider对读写那些对你的应用来说是私有非公开的数据来说同样有用。例如,Note Pad事例使用了一个content provider来保存笔记。

通过继承ContentProvider来实现content provider,并且必须实现能让其他应用执行事务的一套标准API。阅读Content Provider开发指南来了解更多信息。

Broadcast receiver
broadcast receiver 是响应系统级广播通知的组件。许多广播都是由系统发起的,例如,通知屏幕已关闭,电量不足,或者拍照都会触发广播。应用也可以实例化广播,例如,可以通知其他应用某些数据已经下载到设备上供它们使用。尽管broadcast receivers并不显示用户界面,但是当通知发生时它们可以create a status bar notification来告知用户。更常见的是,broadcast receiver仅仅是其他组件的“入口”,自身仅处理很少的工作。例如,它可能实例化一个service来执行基于事件的任务。

通过继承BroadcastReceiver来实现broadcast receiver,每个broadcast用Intent对象发起。 阅读BroadcastReceiver类来了解更多信息。

Android系统设计的一个独特之处在于,任何一个应用都能启动其他应用的组件。例如,如果你想要用户使用设备的摄像头拍摄照片,很可能已经有别的应用实现了这个功能,而你的应用可以直接使用它,而不是再亲自开发一个带拍照功能的activity。你不必把这个相机应用的代码包含进来甚至连链接都不需要。相反,你只需简单的启动相机应用一个可以拍照的activity。当拍照完成后,照片会被回传到你的应用,然后你可以使用它了。对用户来说,就好像相机属于你应用中的一部分。

当系统启动一个组件时,它会开启这个应用的进程(如果还没有运行的话)并且实例化这个组件需要的类。例如,如果你的应用启动了相机应用中用来拍照的activity,那么这个activity运行在属于相机应用的进程中,而不是在你应用的进程中。因此,不像与绝大多数其他系统的应用不同,Android应用没有一个唯一的入口(也就是没有main()函数)。

因为系统把每个应用运行在有文件权限的独立的进程中,这样就限制了对其他应用的访问,因此你的应用不能直接激活其他应用的组件。然而Android系统是可以的。所以如果要激活其他应用中的组件,你必须向系统发送一条带有描述你启动某个组件意图的消息。然后系统会为你激活该组件。

激活组件

上面四种类型组件中的三种(activity、service和broadcast receiver)是被称为intent的异步消息激活的。intent会在运行时把各个独立的组件绑定起来(你可以把它们理解成消息发送者,可以发出调用其他组件的请求消息),不管这些组件是属于你的应用还是别的应用。

intent是使用Intent对象构造的,它可以定义激活特定的组件或特定类型的组件的消息,intent既可以是显示的也可以是隐式的。

对于activity和service来说,intent定义了要执行的操作(例如,去“预览”某物或“发送”某事),而且有可能指定了操作需要处理数据的URI(除此之外可能还需要知道要启动的组件) 。例如,intent可能为activity表达一个显示图片或打开网页的请求。在某些情况下,你可以启动一个activity来获取结果,在这种情况下,activity也会用Intent来返回结果(例如,你可以发出一个让用户选择联系人的intent,然后包含被选中联系人信息URI的intent会返回给你)。

对于broadcast receiver,intent只是简单的定义了正在广播的通知(例如,用来表明设备电量低的通知仅包含一个已知的来描述“电量低”的行为字符串)

对于其他类型组件,content provider不能用intent激活。而是在被来自ContentResolver的请求列为目标时才会被激活。content resolver处理所有关content provider的直接事务,这样执行事务的组件就不需要使用provider了,而是调用ContentResolver对象里的方法。这样在content provider和请求信息的组件之间放置一个抽象层会更加安全。

下面是激活每种类型组件的几个方法:

  • 可以通过把Intent传递给startActivity()或startActivityForResult()(当你想要activity返回结果时使用)来启动activity(或者添加一些新的功能)。
  • 可以通过把Intent传递给startService()来启动service(或者给正在运行的服务添加新的指令)。或者你可以把Intent传递给bindService()来绑定service。
  • 可以通过把Intent传递给诸如sendBroadcast()、sendOrderedBroadcast()或sendStickyBroadcast()方法来发起broadcast。
  • 可以通过在ContentResolver上调用query()方法对content provider执行查询。

更多关于使用intent的信息,请阅读Intents and Intent Filters文档。在下面列举的Activities、Services、BroadcastReceiver和Content Providers文档中也提供了更多关于激活指定组件的信息。

manifest文件


在Android系统可以启动某个应用组件之前,必须通过读取应用的AndroidManifest.xml文件(“manifest”文件)了解该组件是否存在。你的应用必须在manifest文件里应用项目的根目录中声明它的所有组件。

为了声明应用组件,manifest做了许多工作,例如:

  • 确认应用需要的所有用户权限,例如访问网络或读取用户联系人。
  • 根据应用使用的API声明应用需要的最小API Level
  • 声明应用使用或需要的软硬件特征,例如相机、蓝牙服务或多点触摸屏幕。
  • 声明应用需要连接的API库,例如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属性指定用来标识应用图标的资源。

<activity>元素中,android:name属性指定Activity子类的全限定类名,android:label属性指定用作activity的用户可见标签字符串。

你必须用这样的方式声明所有的应用组件:

  • <activity>元素声明activity
  • <service>元素声明service
  • <receiver>元素声明broadcast receiver
  • <provider>元素声明content provider

如果包含在源代码中的activity、service和content provider没有在manifest中声明,那么它们对于系统来说是不可见的,因此不会被执行的。然而,broadcast receiver既可以在manifest中声明,也可以在代码中动态创建(BroadcastReceiver对象)并且通过调用registerReceiver()注册到系统中。

要了解更多关于如何为你的应用构建manifest文件的信息,请参阅The AndroidManifest.xml File文档。

声明组件的功能

正如在上面激活组件(Activating Components)章节中讨论的,你可以使用Intent来启动activity、service和broadcast receiver。你可以通过在intent中明确地指定目标组件(使用组件的类名)来达到启动组件的效果。然而,intent的真正威力在于隐式intent的概念。隐式intent只需要描述要执行操作的类型(并且你也可以视需要描述操作要处理的数据),系统会在设备上寻找能执行该操作的组件并启动它。如果有多个组件可以执行intent描述的操作,那么用户可以从中挑选一个使用。

系统通过把接收到的intent与设备上其他应用中manifest文件里的注册的intent filter进行比较的方式来识别可以响应intent的组件。

当你在应用中的manifest中声明activity时,你还可以在activity里包含能声明activity功能的intent filter,这样它就可以响应其他的应用的intent了。要为你的组件声明intent filter,你可以为组件的声明元素添加一个<intent-filter>子元素。

例如,如果你构建了一个带有可编写新邮件功能activity的邮件应用,你可以像这样声明一个响应“send”intent(为了编写新邮件)的intent filter:

<manifest ... >    ...    <application ... >        <activity android:name="com.example.project.ComposeEmailActivity">            <intent-filter>                <action android:name="android.intent.action.SEND" />                <data android:type="*/*" />                <category android:name="android.intent.category.DEFAULT" />            </intent-filter>        </activity>    </application></manifest>

然后,如果其他应用创建了带有ACTION_SEND类型action的intent并把它传递给startActivity()的话,系统可能会启动你的activity以便用户可以编写发送邮件。

要了解更多关于创建intent filter的信息,请参阅Intents and Intent Filters文档。

声明应用的需求

市场上有许多基于Android的设备,但是并不是所有设备都有同样的功能和特征。为了避免你的应用被安装到缺少应用需要特征的设备上,在manifest文件中通过声明设备和软件的需求来为你的应用支持的设备类型清晰的定义好属性是非常重要的。大部分的声明仅仅是报告作用,系统不会去读取他们,但是诸如Google Play的外部服务为了在用户为他们的设备搜索应用时提供过滤功能则需要读取这些信息。

例如,如果你的应用需要相机并且至少需要Android 2.1(API等级7),你应该在你的manifest文件中像这样声明需求:

<manifest ... >    <uses-feature android:name="android.hardware.camera.any"                  android:required="true" />    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />    ...</manifest>

现在,没有相机的或Android版本低于2.1的设备将不能从Google Play安装你的应用。

当然,你也可以声明你的应用使用相机,但是并不需要它。这种情况,你必须把required属性设置为“false”并且在运行时不管设备有没有相机都要检查,还要尽可能的禁用任何相机功能。

要了解更多关于如何在不同的设备上管理应用组件的信息,请参阅Device Compatibility文档。

应用资源


Android应用不只是仅用代码组成的,还需要与代码分开的资源, 例如图像、音频文件和任何与应用的视觉展示相关的。例如,你应该定义使用XML文件来定义动画、菜单、颜色和用户界面的activity。使用应用资源可以在不修改代码的前提下更新应用的多种特性,并且可以通过提供多种可替代资源为多种设备配置(例如不同的语言和屏幕尺寸)优化应用。

对于你包含在Android工程里的每一个资源,SDK构建工具会为它们定义唯一的整型ID,你可以在你应用代码里或在其他定义在XML里的资源中引用该资源。例如,如果你的应用包含一个名为logo.png的图片文件(保存在res/drawable/目录中),SDK工具会生成一个名为R.drawable.logo的资源ID, 你可以使用它来引用图片插入到你的用户界面中。

把资源与源代码分开的非常重要的一个目的是为了让你能为不同设备配置提供可替代择的资源。例如,通过在XML中定义UI文本,你可以把文本翻译成其他语言,然后保存在不同的文件中。然后,基于你添加到资源目录名称的语言限定符(例如表示法国文本资源的res/values-fr/)和用户的语言设置,Android系统会为UI提供合适的语言文本。

Android可以为你的可替代资源准备了多种不同的限定符。限定符是一种短小的文本,你可以把它包含在你的资源目录名称中,这样就可以为那些应该被使用的资源定义设备配置。再如,你应该根据设备屏幕的方向和尺寸为你的activity创建不同的布局。例如,当屏幕尺寸在竖屏状态时(高),你可能想要一种内部按钮竖着排列的布局,但是当屏幕在横屏状态时(宽),这些按钮应该水平对齐。要根据方向改变布局,你可以定义两种不同的布局,然后为每种布局的目录名添加合适的限定符。然后,系统会根据当前设备的方向应用合适的布局。

要了解更多关于你可以包含在应用中的各种资源和如何为不同设备配置创建可选择资源的信息,请参阅Providing Resources。

继续阅读:

Intents and Intent Filters
关于如何使用IntentAPI去激活组件的信息,例如activity和service,还有如何使你的组件对其他应用可用。
Activities
关于如何创建Activity类实例的信息, 可以在你的应用中为用户界面提供独特的屏幕。
Providing Resources
关于Android应用如何被与应用代码分开的资源构建的信息,包括如何为指定设备配置提供可替代资源。

你可能感兴趣:

Device Compatibility
关于Android在不同类型设备上的信息,介绍了如何为不同设备提供优化或限制你的应用在不同设备上的可用性。
System Permissions
关于Android如何使用权限系统限制应用访问那些需要用户授权API的信息。
3 0