转载

[译] Android 基础

应用程序基础

Android应用程序是用Java编程语言来写的。Android软件开发包(SDK)将你的代码——连同一些数据和资源文件——编译成以.apk为后缀名的APK文件:Android package。一个APK文件包含了一个Android应用程序所有的内容,是运行Android系统的设备用来安装应用程序的文件。

一旦安装到了设备上,每个应用程序都存在于它自己的安全的砂箱里:

  • Android操作系统是一个多用户的Linux系统,其中的每个应用程序都是不同的用户。
  • 默认情况下,系统为每一个应用程序分配一个唯一的Linux用户ID(这个ID只有系统可以使用,应用程序是无法知道的)。系统为应用程序的所有文件设置了权限,因此只有被分配了用户ID的应用程序可以访问。
  • 每一个进程都有它自己的虚拟机(VM),所以一个应用程序代码的运行是与其他应用程序隔离开的。
  • 默认情况下,所有的应用程序运行在它自己的Linux进程里。当应用程序的组件需要被执行的时候,Android就会开始一个进程,而当这个进程不再需要的时候或者系统需要为其他应用程序释放内存的时候,这个进程就会被关闭。

这样,Android系统实行了 最小权限原则 。即每个应用程序在默认的情况下,只能进行它的组件要求它做的工作而不能做更多。这就创造了一个非常安全的环境,在这种环境下应用程序不能访问系统没有给它权限的部分。

然而,应用程序有与其他应用程序共享数据和获取系统服务的方法。

  • 可以为两个应用程序分配同样的用户ID,这样它们就可以互相访问对方的文件。为了保护系统资源,拥有相同用户ID的应用程序可以运行在同一个Linux进程里并且分享同一个VM(应用程序还必须被分配相同的证书)。
  • 应用程序可以请求访问设备数据的权限,比如用户的通讯录,SMS短信,安装存储(SD卡),相机。蓝牙等等。应用程序的所有权限必须在安装的时候被用户授予。

这包括了一个应用程序如何在系统中生存的基础知识。这篇文章接下来将向您介绍:

  • 定义你的应用程序的核心组件框架。
  • 为你的应用程序声明框架和请求设备功能的清单文件。
  • 与应用程序代码隔离开来的资源并且使你的应用程序可以在各种不同配置的设备中从容地进行优化。

应用程序组件

应用程序组件是Android应用程序里不可缺少的组成模块。每个组件都是系统可以进入你的应用程序的入口。不是所有的组件都是用户的入口,其中一些组件还依赖其他组件,但是每一个组件都作为一个它自己的实体存在并且扮演了一个具体的角色——每一个组件都是帮助你定义你的应用程序的整体行为的独特模块。

应用程序组件有四种。每个组件都服务于不同的目的并且有定义了各自如何创建和销毁的不同的生命周期。

下面是这四种应用程序组件

Activitys

Activity 表示一个用户界面的一个单独的屏幕。例如,一个邮件应用程序可能有一个用来展示一系列邮件的Activity,一个用来撰写邮件的Activity,一个用来阅读邮件的Activity。尽管这些Activity共同作用在一个邮箱应用程序里形成一个有凝聚力的用户体验,但是每一个Activity都是相互独立的。因此,一个不同的应用程序可以由其中的任何一个Activity开始(如果这个邮件应用程序允许这么做)。比如,用户为了分享一张照片,可以从一个邮件应用程序的撰写邮件的Activity里面开启一个照相机Activity。

一个Activity是实现了 Activity 的子类,你可以在 Activity 开发指南中学习更多有关Activity的知识。

Services

services 是一个为了进行长时间运行的操作或是进行远程进程而运行在后台的组件。service不提供用户接口。比如,当用户在使用其他应用程序的时候,一个service可能在后台播放音乐,或者从网络上获取数据而不阻塞用户与当前的Activity之间的交互。其他组件,比如Activity,可以开启一个service让它运行或者与service绑定进行交互。

一个service是实现了 Service 的子类,你可以在 Service 开发指南中学习更多有关Service的知识。

Content providers

content provider 是管理一个应用程序的数据的共享集合。你可以将数据保存在系统文件、SQLite数据库、web端、或者是其他任何你的应用程序可以读取到的本地持久性存储中。通过content provider,其他应用程序也可以读取甚至修改数据(如果content provider允许的话)。比如,Android系统提供了一个content provider来管理用户的通讯录信息。那么,任何拥有正确权限的应用程序都可以询问content provider的一部分(比如 ContactsContact.Data )来读取或写入某个人的信息。

content provider对于你的应用程序的私人和非共享数据的读写也是有用的,比如,应用程序 Note Pad 用content provider来保存笔记。

content provider是实现了 Content Provider 的子类,并且必须实现标准的API集以使其他应用程序可以执行事务。你可以在 Content Provider 开发指南中学习更多有关Content Provider的知识。

Broadcast receivers

broadcast receiver 是一个可以响应全系统的广播通知的组件。很多广播来自于系统——比如,一个广播通知屏幕被关闭、电量过低、一张图片被抓获。应用程序也可以开始一个广播——比如,让其他应用程序知道有数据被下载到了设备上并且它们可以使用这些数据。虽然broadcast receiver不能显示一个用户界面,但是当一个广播事件发生时,broadcast receiver可以创建一个 状态栏通知 来提醒用户。更常见的情况是,broadcast receiver相当于其他组件的“网关”并且只有很少的工作量。

broadcast receiver是实现了 BroadcastReceiver 的子类并且每一个broadcast被作为一个 Intent 对象。你可以在 BroadcastReceiver 开发指南中学习更多有关BroadcastReceiver的知识。

Android系统设计的独特之处在于任何一个应用程序都可以开启其他应用程序的组件。比如,如果你想让用户使用照相机拍摄一张照片,可能是由其他应用程序来做这件事而你的应用程序可以使用它。你不需要从照相机应用程序中合并或者连接代码。事实上你只需要打开照相机应用程序里的用来拍照的Activity。当拍照完成后,这张照片甚至可以返回到你的应用程序里从而让你可以使用它。对于用户来说,照相机看起来就像是你的应用程序中的一部分。

当系统打开一个组件时,就为你的应用程序开启了一个进程(如果该组件当前没有在运行)并且为当前组件实例化了一个需要的类。比如,当你的应用程序开启一个照相机应用程序里用来拍照的Activity时,这个Activity运行的进程属于照相机应用程序而不属于你的应用程序。因此,不像其他大多数系统里的应用程序,Android应用程序并不只有单一的入口(比如Android应用程序没有 main() 函数)。

激活组件

四种组件里面的三个——activities,services和broadcast receivers——是被一个叫做 intent 的异步消息激活的。Intent将每一个单独的组件同其他正在运行的组件联系起来(你可以将它想象为从其他组件请求行为的信使),而不管其他组件属于你的或是其他的应用程序。

一个intent连同一个 Intent 对象一起被创建,它定义了一个被用来激活或者是一个特定组件或者是一个特定类型组件的消息——一个intent可以分别是显式的和隐式的。

对于Activity和service来说,一个intent定义了一个要执行(比如,“看”或“发送”一些东西)的操作并且指定了URI中的数据作用于何处(在该组件被启动可能需要知道的其他东西)。比如,一个intent可能会向Activity传递一个展示图片或者打开网页的请求。在一些情况下,你可以打开一个Activity来接收一个返回值,在这种情况下Activity也向Intent返回一个返回值(比如,你可以发出一个Intent让你的用户选择一个个人联系并让他返回给你——这个返回的Intent包含了一个指向被选择的联系的URI)。

对于broadcast receivers,intent仅仅定义了将要被发送出来的通知(比如,一个表明了设备电量过低的broadcast仅仅包含了一个操作字符串“电池电量过低”)。

另一种组件,content provider,不是由intent来激活的,而是有针对性地由一个来自 ContentResolver 的请求来激活。content resolver处理所有与content provider的直接交易,这样使得所有与provider进行交易的组件不需要,而是直接调用ContentResolver对象的方法。这样就给出了content provider与组件之间请求信息的一层抽象(为了安全)。

下面是另外几个激活各种组件的方法。

  • 你可以向 startActivity() ,或 startActivityForResult() (如果你想要Activity返回数据)传递一个 Intent 来开启一个Activity(或者让它做一些其他东西)。
  • 你可以向 startService() 传递一个 Intent 来开启一个service,或者你可以向 bindService() 传递一个 Intent 来绑定一个service。
  • 你可以向类似于 sendBroadcast() , sendOrderedBroadcast() 或 sendStickyBroadcast() 的方法传递一个 Intent 来开启一个broadcast。
  • 你可以在 ContentResolver 中调用 query() 方法来向content provider进行查询。

你可以在 Intents and Intent Filters 文档里得到有关intent的更多信息。下面这些文档提供了更多关于激活特定组件的信息: Activities , Services , BroadcastReceiver 和 Content Providers 。

清单文件

在Android系开启一个应用程序组件之前,系统必须通过读取 AndroidManifest.xml 文件(即manifest文件)来获悉有哪些组件存在。你的应用程序必须在manifest文件中声明它的所有组件,它必须在应用程序项目目录的根目录。

除声明应用程序的所有组件之外,manifest文件还要做很多事,比如:

  • 鉴定应用程序需要的所有用户权限,比如获取Internet连接或者读取用户通讯录的权限。
  • 声明应用程序所需要的最低API版本,以及该应用程序的使用基于哪个API版本。
  • 声明应用程序用到的和需要的硬件和软件特征,比如照相机,蓝牙服务或者是多点触控屏。
  • 应用程序需要连接的API库(除Android框架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>

元素里, android:icon 属性指向识别该应用程序的图标资源。

元素里, android:name 属性指定了 Activity 的子类的完整类名; android:label 属性为Activity指定了一个用户可见的字符串标签。

你必须像这样声明应用程序的所有组件:

  • activitie的 <activity> 元素
  • service的 <service> 元素
  • broadcast receiver的 <receiver> 元素
  • content provider的 <provider> 元素

包含在你的资源中但是没有在manifest文件中声明的Activities, services, 和 content providers是对系统不可见的,通常也不能被运行,但是broadcast receivers既可以在manifest中声明也可以在代码里动态创建(作为 BroadcastReceiver 对象),并且通过调用 registerReceiver() 在系统中注册。

想知道更多关于如何在你的应用程序中构建manifest文件的信息,请查阅 The AndroidManifest.xml File 。

声明组件的作用

如同在上面 激活组件 里讨论过的一样,你可以通过 Intent 来开启一个activities, services, 和 broadcast receivers。你可以通过在intent中明确地命名目标组件(用组件类名)来开启它们。然而,intent的真正能力在于 implicit intents 这个概念。一个implicit intents仅仅描述了将要执行的动作的类型(也可以选择你要执行的动作中的数据)并且允许系统在你的设备上寻找一个可以执行该动作的组件然后开启这个组件。如果设备上有多个组件可以执行intent所描述的动作,那么用户将选择使用哪一个组件来执行。

系统识别出可以响应一个intent的组件的方法是通过比较设备上的其他应用程序提供的清单文件中的 intent filters 收到的intent。

当你在你的应用程序的manifest里面声明一个Activity的时候,你可以选择性地加入声明了Activity的作用的intent filters,以使这个Activity可以响应来自其他应用程序的intent。你可以通过添加一个 <intent-filter> 元素作为组件的声明元素的子元素来为你的组件声明一个intent filter。

比如,你已经构建了一个拥有可以撰写邮件的Activity的邮件应用程序,你可以像这样声明一个intent filter来响应“发送”这个intent(为了发送一个Email):

<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 操作的intent并且将它传入 startActivity() ,系统就会开启你的Activity以使得用户可以撰写并发送邮件。

想知道更多关于构建intent filter的信息,请查阅 Intents and Intent Filters 。

声明应用程序请求

运行Android操作系统的设备多种多样,并且不是所有的设备都有相同的外观和配置。为了防止你的应用程序被安装到那些缺少你的应用程序需要的功能的设备上,通过在你的清单文件中声明对设备和软件的需求来清晰地确定你的应用程序所支持的设备类型是很重要的。这些声明大部分都仅供参考,系统不会去读它,但是一些外部服务,比如Google Play,会在用户搜索设备上的应用程序时读取它们从而为用户提供过滤。

比如,如果你的应用程序需要使用照相机并且你使用了Android 2.1 ( API Level 里介绍的API,你需要向下面这样在你的清单文件中声明请求:

<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,你就可以通过这个ID引用这张图片并且将其插入到你的用户界面中去。

提供从你的源代码中分离出来的资源的最重要的方面是为不同配置的设备提供资源的能力。比如,在XML文件中定义用户界面的字符串,你可以把这些字符串翻译成其他语言并且保存在分离的文件中。接下来,根据你附加到资源目录名称的语言修饰词和用户的语言设置,Android系统将会在你的用户界面中应用合适的语言字符串。

Android为你的资源支持很多修饰词。修饰词是包含在你的资源目录名字中为了定义你的设备配置应该使用何种语言的短的字符串。另一个例子,你经常要视你的屏幕方向和尺寸的不同而为你的Activity创建不同的布局。比如,当你的设备屏幕是纵向的时候,你希望拥有一个将按钮垂直排列的布局,但是当设备屏幕是横向的时候,按钮应该水平对齐。为了视屏幕方向而改变布局,你可以定义两种不同的布局并且为两种布局的目录采用适当的修饰词。接下来,系统将会自动地视当前设备屏幕的方向来应用适当的布局。

想知道更多种你可以包含在你的应用程序中的资源和如何为不同配置的设备创建替代资源,你可以阅读 Providing Resources 。

深入阅读

Intents 和 Intent Filters

在这里可以了解到如何使用 Intent 来激活应用程序组件例如Activity和service,以及如何使你的应用程序组件在其他应用程序中可用。

Activity

在这里你可以了解到如何为Activity类创建一个实例,它为你的应用程序的用户界面在每一种设备中都提供了一个独特的屏幕。

Providing Resources

在这里你可以了解到Android应用程序是如何从代码中结构化地分离出资源的,以及如何为特定配置的设备提供替代资源。

你或许对这些内容感兴趣

Device Compatibility

在这里你可以了解到Android是如何在不同种类的设备上工作的,还会介绍如何为每种设备优化你的应用程序或者在不同的设备上限制你的应用程序的功能。

System Permissions

在这里你可以了解到Android如何使用权限制度限制你的应用程序读取某些API,需要为你的应用程序使用这些API征得用户同意。

原文地址

正文到此结束
Loading...