Android应用程序开发笔记之Fundamentals

在Android系统上安装了一个应用程序之后,该应用程序就会有一个它自己的安全沙箱:

  • Android操作系统是一个多用户的Linux系统,每个应用程序就是其中的一个用户
  • 每个进程一个虚拟机(VM),所以应用程序间的代码运行是相互独立的。
  • 默认地,系统分配每个应用程序一个唯一的用户ID(用户ID只对系统可见,对应用程序来说是不可见的)。系统会对应用程序的文件设置权限,只有拥有该应用程序的用户ID才可以访问这些文件。
  • 默认地,每个应用程序运行在它自己的Linux进程。系统在需要用到应用程序组件时开启进程,在不再需要用到应用程序或需要为其他应用程序回收系统资源时结束进程。
在这种方式下,Android系统实现了最小权限原则。即默认地情况下,应用程序除了能调用组件工作之外,就不能做其他事了。这样就创造了一个非常安全的环境。应用系统只有在赋予权限的情况下才能访问系统的其他内容。
但是,也有许多方式让你的应用程序给其他的应用程序共享数据并访问系统服务:
  • 两个应用程序可以共用相同的Linux用户ID,那么它们就可以互相访问各自的文件。为了节省系统资源,带相同用户ID的应用程序也可以运行在相同的Linux进程和相同的VM(应用程序间必须签名相同)
  • 应用程序可以请求权限访问设备的数据,像联系人,SMS短信,SD card,摄像头,蓝牙等等。所有权限必须在安装的时候授与应用程序。

应用组件

一共有4种不同类型的应用组件。每种类型都有明确的用途和清晰的生命周期。

Activities:一个activity描绘了一个单独的用户界面。例如:一个email的应用程序会有一个activity显示email列表,一个activity编辑email,一个activity查看email的内容。虽然这些activity结合起来形成非常好的用户体验,但每个activity是独立的个体。所以,其他的应用程序可以运行这些activities中的一个(如果email应用程序允许的话)。例如,一个camera应用程序可以启动email应用程序的activity来编辑一封带刚刚照的照片的新的email。

Services:service是运行在后台来完成一个长期运行的操作或为完成远程进程的工作。service没有用户界面。例如:service可以在后台播放音乐的时候,用户可能在使用其他的应用程序,或者service通过网络获取数据的过程中不会妨碍用户与activity的交互。其他的像activity的组件,可以开启或绑定service。

service是通过继承Service来实现的。

Content providers:content provider管理着一份共享的应用数据。你可以保存数据在文件系统、SQLite数据库、网络或者其他你的应用程序可以访问的持久化存储地址。其他应用程序可以通过content provider查询或修改数据(如果content provider允许的话)。例如,Android系统提供了一个content provider来管理用户的联系人信息。因此,任何拥有合适权限的应用程序可以查询部分的content provider(像ContactsContract.Data)来读写一个指定联系人的信息。
Content providers同样可以读写你的应用程序的私有化数据(不会共享给其他应用程序)。例如,Note Pad样例就是使用了content provider来保存notes。
content provider通过继承ContentProvider来实现并且必须实现一套标准的API让其他应用程序完成交互。
Broadcast receivers:broadcast receiver是一个能响应系统级别广播事件的组件。许多的广播事件来源于系统,像屏幕关闭、电量过低,或照了一张照片的广播事件都是来源于系统。应用程序也可以发布广播事件,像告诉其他应用程序某些数据已经下载完成并且这些数据可以供使用了。虽然broadcast receiver不会显示用户界面,但他们可以创建一个状态栏通知来提醒用户有一个广播事件发布了。更普遍的情况是,broadcast receiver仅仅是其他组件的“切入口”来完成少量的工作。例如,它可以基于广播事件来开启一个service来完成一些工作。
broadcast receiver是通过继续BroadcastReceiver来实现的,并且广播事件是通过Intent对象来传递的。
Android系统的一个独特的设计是任何一个应用程序都可以启动其他的应用程序。例如,如果你想在你的应用程序中让用户照一张照片,那么你只需要调用一个camera应用程序activity来完成这个工作,而不需要你另外编写一个activity来完成照相任务。在用户的角度来看,这个照相的功能像是你的应用程序的一部分。
当系统启动某个应用程序的组件,那么它就会启动该程序的进程(如果该程序没有在运行的话)并且实例化组件所用到的类。例如,你的应用程序启动了camera应用程序的一个activity来照相,那么该activity会运行在需要camera应用程序的进程而不是运行在你的应用程序线程。因此,android应用程序不像其他系统的应用程序,它不会有一个单独的程序入口(像main()方法)。

激活组件

activities, services, and broadcast receivers组件由一个称为intent的异步信息激活。在运行时,Intent绑定一个组件(你可以想像成一个来自其他组件的请求信息), 不管这个组件是否属于你的应用程序。
Intent通过Intent对象生成,它定义了一个指定的组件或一个指定类型的组件——intent可以被明确指定或暗含指定。
对于activity和service来说,intent定义了需要完成的动作(例如,"查看"或"发送"一些东西)并且可以指定将要用到的数据的URI(还有其他一些组件运行时需要知道的东西)。例如 ,intent可以发送一个请求给一个activity显示一张图片或打开一个网页。有些时候,你还可以通过intent获取activity运行的结果(例如,你可以发送一个intent获取一个联系人信息——返回的intent包含了指向该联系人信息的URI)。
对于broadcast receiver来说,intent只简单地定义广播事件的内容(例如,一个指示设备电池量低的广播事件仅仅是一个已知的动作字符串“battery is low”).
对于另一个组件content provider,它并不是通过intent激活的。然而它是通过ContentResolver发送请求来激活的。content resolver掌管了所有与content provider的直接交易,所以其他组件只需要调用ContentResolver对像的方法,而不需要与content provider打交道。这就是为了安全起见,所以在content provider与组件信息请求之间保留了一个抽象层。

有以下方法来激活组件:

  • activity可以通过传递一个Intent给startActivity()方法来激活(或传达新任务给activity),或startActivityForResult(Intent intent,int requestCode)来激活一个有返回结果的activity。
  • service可以通过传递一个Intent给startService()方法来激活(或传递新的信息给一个正在运行的service),或者通过bindService()方法绑定service。
  • 创建广播事件可以通过传递一个intent给sendBroadcast()、sendOrderedBroadcast()或sendStickyBroadcast()方法。
  • 调用ContentResolver的query()方法来完成数据查询。

Manifest文件

android系统在激活一个应用组件之前,必须通过读取应用程序AndroidManifest.xml文件来获知该应用程序是否包含有该应用组件。你的应用程序必须在应用根目录下包含有AndroidManifest.xml文件,并声明所有需要用到的应用组件。

manifest文件除了声明组件外,还有以下用途:

  • 鉴别应用程序请求的用户权限,像网络访问权限或读写访问用户联系人。
  • 声明应用程序使用的最低的API版本
  • 声明需要使用的或应用程序必须用到的硬件和软件特征,像摄像头,蓝牙服务,多触点触摸屏。
  • 应用程序需要用的到API库(非Android framework APIs),像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属性指向一个用于分辨应用程序的icon资源
在<activity>元素中,android:name属性指定了Activity对象的全限定类名,android:label属性指定了一个用户可见的字符串标签。
用以下元素来声明应用组件:
  • activity:<activity>
  • service:<service>
  • broadcast receivers:<receiver>
  • content provider:<provider>
要是你的activity,service和content provider没在manifest中声明的话,那么对于系统来说你的这些组件是不可见的,并且不会被运行。然而,broadcast receiver可以在manifest中声明也可以动态地在代码的通过方法registerReceiver()来注册。

声明组件的功能

像上面所说的,在activity组件中,你可以通过Intent来激活activity,service和broadcast receiver。Intent可以明确地指定全限定类名的应用组件。然而,真正强大的intent依赖与intent的action(以后称为:动作)的概念。你可以简单地指定你想要完成的动作(还可以指定完成该动作所需的数据)并要求系统去找能完成该动作的应用组件并激活它。如果会有多个应用组件可以完成该动作,那么会让用户选择一个来运行。

应用程序通过对比接收到的intent与各应用程序在manifest文件中声明的intent filters来确定哪些组件可以响应这个动作。

当你在manifest中声明应用组件的时候,你也可以通过intent filter 来声明组件的功能。你可以在manifest的应用组件元素下添加<intent-filter>元素来声明intent filter。

例如,email应用程序中的编辑email的activity可以声明intent filter来响应带"send"动作的intent。那么你的应用程序可以创建一个带"send"动作的intent,来激活email程序的activity。

声明应用程序的要求

android系统可以支持很多不同的硬件设备,但这些设备未必有相同的功能或特征。为了防止你的应用程序安装在一个缺少设备特征功能的环境下,你可以在manifest中明确地声明设备和软件要求。这些声明只是一些文字信息,系统也不会读取他们,但一些额外的service,像Android Market,会读取他们,为用户过滤掉一些不适合他们设备的应用程序。

例如,如果你的应用程序需要用到摄像头和基于Android 2.1 API,你可以声明这些要求在你的manifest文件。这样的话,一台没有摄像头的,android版本低于2.1的机器将不能从Android Market安装你的应用程序。

然而,你也可以声明你的应用程序需要用到摄像头,但不是必须的。在这种情况下,你的应用程序必须在运行时检查机器是否带有摄像头,如果机器不带摄像头,那么禁用摄像头那部分的功能。

在你设计开发你的应用程序的时候,你需要考虑一下下面的一些重要的设备参数:

  • 屏幕大小和分辨率:Android定义了屏幕大小与分辨率这两个参数来将设备归类。为了简化所有不同类型的屏幕配置,Android系统把它们概括成几个组。屏幕大小分为:small,normal,large和extra large。屏幕分辨率分为:low density,medium density,high density和extra high density。默认地,你的应用程序兼容所有的屏幕大小与分辨率,因为android系统会自动地调整你的UI层和图片资源。然而,你需要为某些屏幕大小提供特定的层和为某些分辨率提供特定的图片,并在manifest中通过<supports-screens>元素声明你的应用程序支持多大的屏幕。
  • 输入配置:不同的设备提供了不同类型的用户输入机制,像物理键盘,追踪球或five-way navigation pad。如果你的应用程序要求一个特殊类型的输入硬件,那么你需要在你的manifest中用<uses-configuration>元素声明。不过,很少应用程序要求一个特定的输入配置。
  • 设备特征:有些机器可能会没有一些软硬件的特征,像摄像头,光感应,蓝牙,某个版本的OpenGL或屏幕的准确度。因此你需要在manifest中使用<uses-feature>元素声明设备特征。
  • 平台版本:在manifest中通过<uses-sdk>元素声明最低的API版本。

应用程序的资源

android应用程序并不只有代码,还有其他的资源,像图片,声音文件等。例如,你需要定义动画,菜单,样式,颜色值,布局。使用应用程序资源可以在不修改源码的情况下轻松地更改应用程序的许多特征。

相关推荐