Android Application Fundamentals

原文链接:http://developer.android.com/guide/components/fundamentals.html

 

Application Fundamentals(应用基本原则)

   Android app 使用java语言编写。Android sdk tools 编译代码连同数据与资源文件,形成一个以.apk为后缀的android pacckage 最终文件。所有代码在单独.apk 文件中被认为是一个独立的application且 android-powered 设备使用该文件安装application.

一旦被安装在一台设备中,每一个android-app存活在自己独立安全沙盒(security sandbox:

l Android 操作系统是一个多用户linux 系统,该系统中将每一个app作为不同的用户

l 默认情况下,系统分配给每个app唯一的linux 用户id(id仅仅被系统使用,对于app是未知的)。系统对app中的所有文件设置了权限,以至于只有将用户id分配给app才能操作这些文件。

l 每一个程序都有它独自的虚拟机器(vm),所以一个app的代码运行独立运行与其他程序隔离.

l 默认情况下,每一个app运行各自的linux 进程(linux process).Android 启动进程当application的任何一个组件启需要被执行时,当app不在被执行时,或者是系统必须回收(recover) 内存用于其他app时,app将被关闭。

 

在这种情况下,android系统继承了最小权限原则(least privilege.也就是说,每个app在默认情况下,只能根据自己的需求操作相应的组件不能做其他更多的事情。这样的原则保证了一个安全的环境使得app不能操作系统的其他部分资源在没有给予权限的情况下。

然而,存在很多方式让app共享数据以及让app操控系统服务:

l 两个app可能会共用一个相同的linux user id,在那种情况下它们可以相互操控对方的文件。为了保护系统资源,共用同一个user idapps将会在同一个linux 进程中运行以及分享同一个VM(apps必须拥有同一个签名)

l App 可以申请操控像用户联系人,短信,sdcard,相机蓝牙其他等设备数据的权限。App所有的权限在安装时被用户授予。

 

以上覆盖了android app如何存在于系统中的基本知识。下面介绍文档的其他部分:

l 定义apps的核心框架组件

l Manifest 文件申明组件的文件 以及 设备识别你的app

l 资源文件独立于app代码 以及 app优化对应不同的设备配置

 

Application Components

App组件们是构成app的基本模块。每一个组件是一个不同的点让系统可以进入的app.并非所有的组件对于用户以及依赖于该组件的其他模块来说是天然的入口点,但是每一个组件以一个整体存在且扮演了一个特殊的角色-----也是说每一个组件都是唯一构建模块帮助定义app的所以行为

存在四种不同类型的app组件。每一种类型为了达到特殊的目的存在且有特殊的生命周期帮助定义组件如何被创建如何被消亡。

四种apps组件:

Activities:

一个activity代表了一个单独带有用户界面的屏幕。举个例子:一个email app可能存在一个activity显示新email的列表,另一个activity则是用于编辑email,且存在另一个acitivity用于阅读email.虽然这些activity在一起工作构成了email app,每一个activity实际上都是独立的。如此,每一个不同的app可以启用任何一个activity(如何email-app允许的情况下)。举个例子:一个照相机app 可以启用email-app中的 activity 编辑新邮件,为了分享一张图片.

一个activity 将被执行作为Activity的子类,你可以在Activity 开发者教程中学习更多。

 

Services

Service 是一个运行在后台的服务,执行耗时长的操作或者执行远端的进程。一个service不提供用户页面。举个例子,一个service可以在后台播放音乐当用户在使用其他appservice正在从网络端获取数据但不阻塞用户对activity的交互。另一个组件,像是activty,可以启动service 且让它运行或者bind service为了影响service的运行。

 

Content providers

一个content provider管理一个app数据共享的集合。你可以存储数据在文件系统中,一个SQLite database,web端,或者是任何一个持久化存储且你的app可以操控的区域。通过content provider,其他app可以查询甚至修改数据(如果content proivder 允许用户修改)。举个列子,Android 系统提供一个 content provider,它管理用户的联系人信息。像这样,任何一个获取正确权限的app可以查询content provider的部分(例如ContactsContract.Data)去阅读以及修改关于某个人的信息。

 

Content proivders 同时也可以用于阅读与修改数据仅仅对你的app而不是共享的。举个列子,NotePad 样例使用content provider存储notes

任何一个content provider 作为ContentProvider的子类执行,必须实现标准的apis集合使得其他app可以调用处理。

 

Broadcast receivers

broadcast receiver 是一个响应系统范围的广播通知的组件。许多广播来源于系统,例如,一个广播宣布屏幕已经被关闭了,电池电量低或者是一张照片被拍下来了。App也可以生成一些广播,例如,让其他app知道一个数据已经下载到设备且可以被他们使用。虽然broadcast receivcer不同显示用户界面,他们可以生成一些status bar notification 去提醒用户当broadcast发生的时候。更加通用的,一个broadcast receiver是一个通向其他组件的“门槛”且在broadcast receiver中做尽量少的事情。列如:它可以实例化一个service去用一些基于该事件的工作。

 

Android系统一个独特的设计是任何一个app可以启动另一个app的组件。举个例子,如果你想要用户用设备的相机拍一张照片,可能存在另一个app可以实现刚才的操作且你的app可以使用它,而不用自己去开发一个activity去拍摄一张照片。你不需要合并甚至不需要链接摄像机的code.你只需要简单地启动摄像机的app去照一个照片。当完成的时候,照片甚至会返回到你的app这样你就可以使用它了。对于用户来说,摄像机就好像是你的app部分功能一样。

 

当系统启动一个组件的时候,它会为app(如果还没运行)启动一个进程且实例化该组件需要的class.举个例子,如果你的app在摄像机app中启动一个activity去拍照片,那个activity运行的进程属于摄像机app,而不是你的app。因此,不同于app在其他系统中,andorid app没有个单独的入口点(不存在main()函数)

 

因为系统运行每一个app在分离的进程中使用文件权限用于制约其他app的操作,所以你的app的组件不能直接被其他app激活。然而,android 系统,可以直接激活其他app的组件,你必须传递一个msg到系统指定你的intent启动指定的组件。然后系统帮助你激活对应的组件。

 

激活组件

四种组件类型中的三种,activityservicesbroadcast receivers 可以被一种异步的信息激活,这种信息命名为intent. Intents在运行的时候绑定指定的组件(你可以认为它们做为一个发送消息者请求其他组件对应的动作),然而组件属于你的app或者其他。

一个intent 作为一个Intent 对象被创建,它定义了一个可以激活特定组件或是特定类型组件的消息,intent是显式的或是隐式的。

对于activitiesservices,intent 定义一个action去运行(例如,阅览或是发送某些东西)以及可以指定操作使用的URI数据信息(其他一些组件启动所需数据)。例如,intent传达了一个activity展示一张图片或者打开一个web页面的意图。在一些例子中,你可以启动一个activity接受一些运行结果,在那些例子中,activity返回操作结果在一个intent中(例如,你可以发出一个intent让用户挑选一个私人联系人然后返回一个intent包含一个uri点帮助选择联系人)

对于broadcast receivers, intent简单定义被广播的信息(例如,一个广播指明设备电量低包含action字段指明电量低(battery is low))

另一个组件类型,content provider,是不能被intent激活。然而,当一个请求来自ContentResolvercontent provider 可以被激活。Content resolver处理所有有关与content provider的事务(transactions)所以执行provider事务的组件不需要去调用ContentResovler 对象的方法。这种情况保证了在content provider 和组件请求信息之间抽象的分层(为了安全)

 

存在隔离不同的方法激活每种类型的组件:

你可以通过传递一个intent调用startActivity()或是startActivityForResult()(当你想让一个activity返回结果时)来启动activity(或者give it somethine new to do)

你可以通过传递一个intent调用startService()去启动一个service(或者给予一些新的指令给已运行service),或者你可以通过intent调用bindService()绑定一个service

你可以通过传递一个intent调用类似于sendBroadcast(),sendOrderedBroadcastt()或者sendStickyBroadcast()的方式实例化一个广播

你可以执行一个对于content provider查找操作,通过对contentResolverquery()的操作。

 

更多关于使用intents的信息,详见Intents and Intent Filters文档。更多关于激活特定组件信息查看一下文档:AcitivitiesServicesBroadcastReceiver以及Content Providers

 

The Manifest File

Android系统启动一个app组件之前,系统通过阅读appAndroidManifest.xml必须知道组件已经存在。你的app必须声明所有的组件在这个文件中且该文件必须在app工程目录的根目录。

 

Manifest做了以下一些事情以及声明了app组件:

l 申明app所需的用户的权限,网络操作或者对用户联系人的操作

l 申明api最低levelapp所使用的api

l 申明app所使用硬件与软件的功能,像是camera、蓝牙或是多点触控。

l  App所需要的api lib(那些区别于android framework api),像是google maps library

l 更多

 

申明组件

Manifest的首要认识是向系统申明关于app的组件。举个例子,一个manifest 文件可以向下面这样申明一个act

<?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属性指出相应于iconapp可以识别的资源。

 

<activity>元素中,android:name属性要求Activity子类的全部类名以及android:label属性要求使用的字段是对activity可以的。

 

你必须申明所有的app组件这种方式:

<activity>元素对应activity

<service>元素对应services

<receiver>元素对应broadcast revicers

<provider>元素对应content providers

 

Activitiesservices以及content provider在你代码中而没有在manifest中申明对于系统是不可见的,它们是不能被执行的。然而,broadcast receiver 可以在manifest中申明也可以在代码中动态的创建且通过调用registerReceiver()的方式向系统注册。

 

申明组件能力(capabilities)

根据以上讨论,在活跃的组件中,你可以使用一个Intent去启动activityservices以及broadacast receivers.你可以做这样的事情明确指定目标组件(使用组件的类名)在intent中。

但是,实际有效的intents依赖于intent actions的概念。通过使用intent actions,你可以简单地描述你想要展开action的类型(数据根据你想要展开的action)以及允许系统可以找到在设备上的组件可以去展现action并启动它。如果存在多个组件可以展现这个用intent描述action,之后用户选择其中一个去使用。

系统识别可以回应intent的组件方式是通过比较intent可接受的intent filters,这些intent filters在设备上的applicationsmanifest文件提供。

当你在你的application manifest中申明一个组件,你可以随意定义你的intent filters去申明组件的能力,这样它就可以回应来自其他applicationsintent.你可以申明一个intent filter给你的组件,通过添加<intent-filter>元素作为组件的一个子元素。

举个例子,一个email app中的一个activity用于编写一封信的邮件,可能在它的manifest入口申明一个intent filter 去回应 ’send’ intents(为了发送email).一个在你app中的activity可以创建一个intent使用”send”action( ACTION_SEND),这样的化,系统可以匹配intent对用email appsend activity以及展开这个activity当你通过startActivity()调用intent.

 

申明application 需求

存在各种类型由android启动的设备,这些设备提供相同的功能与能力。为了防止你的app所需的功能在设备上没有,你必须清晰地定义一个主页来阐明你的app所支持的设备类型,通过在你的manifest文件中申明设备以及软件需求的方式。大多数的申明只是信息,系统不会阅读它们,但是像google play这类极端服务阅读它们是为了向用户提供过滤,当用户在他们的设备上搜索app时。

例如,如果你的app需要一个摄像机以及使用在android 2.1中介绍的Apis,你需要在你的manifest 文件将这个作为需求申明。那样,如果设备没有摄像机或者android 版本低于2.1不能安装你的appgoogle play 上。

然而,你也可以申明你的camera,但是不用使用它。这样的话,你的app必须在在运行的检查设备是否存在摄像机以及一些功能是否可用,来决定是否使用camera

一些重要的设备特性你需要确定,当你设计开发的你的app时,

 

屏幕的大小与密度(density

为了以设备的屏幕类型来分类,android对于任何设备定义了两种特性:

屏幕大小(屏幕的物理)大小以及屏幕的密度(一个像素在屏幕上的物理密度,或者是dpi-dots inch.为了简化不同类型屏幕的配置,android系统将它们概括成选定的组中让它们更为简单地被操作。

屏幕大小是:small.normal,large.and extra large

屏幕的密度是:low density,medium density,high density and extra hight density

 

在默认的情况下,你的app是兼容所有屏幕大小和密度的,因为android系统会适当的调整的你ui layout以及图片资源。然而,你需要创建特别的layouts用于特定的屏幕大小以及提供特定的图片资源用于特定的密度,使用可替换的layout 资源以及在你的manifest中用<supports-screens> 元素的方法明确申明那种屏幕大小你的app可以支持的方式来实现。

 

输入配置

很多设备提供不同类型的用户输入机制,像是硬件键盘、trackball?)或是a five-way navigation pad(?)。如果你的app需要一种特别的硬件输入方式,你需要在你的manifest中申明它,通过使用<uses-configuration>元素的方式。然而,一个app需要一个特定的输入方式并不常见。

 

设备功能

存在很多的硬件和软件的功能在android启动的设备上可能不存在,像是camera、光敏传感器(light sensor)、bluetooth、特别版本的OpenGL,或者是触摸屏。你不能假设一个特别的功能在任何android设备上都是可用的(除了android标准lib的可用性),所以你需要在你的manifest中使用<uses-feature>去申明你的app所要用的feature

 

平台版本

不同的android 设备经常运行在不同版本的android平台上,像是android1.6或是android2.3.每个连续的版本经常包含附加的Apis,这些apis不能再旧版本中使用。为了说明哪些api是可用的,每个平台版本指向一个api level(例如,android 1.0api level 1,android2.3是 api level 9.如果你使用的任何是在版本1.0之后添加的api,你必须要申明min api level

通过使用<uses-sdk> 元素的方式。

 

申明你app所有的需求(requirements)这个很重要,因为当你在google play中发布你的app时,商店使用这些申明作为过滤去判定哪些app是在设备上可用的。这样的化,你的app通过app 需求可以在对应的设备上使用。

 

App 资源

一个android app 不仅仅由代码构成------它需要资源文件,独立于源代码,像是图片、音频文件以及任何有关于app可见图像。例如,你应该使用xml文件来定义动画、菜单、风格、颜色以及activitiy 用户界面的layout。使用application 资源更新你的app特性更加简单且不用修改代码以及通过提供可替代资源集合让你可以优化你的app来适应不同配置的设备(像是不同语言以及屏幕大小)。

对于任何在你app工程中的资源,sdk build 工具定义一个独特的整型id,你可以通过这个id在你app的代码或者其他xml资源文件中指向该资源。举个例子,如果你的app有个图像资源文件命名为logo.png(保存在res/drawable/ 文件夹下),sdk工具生成一个资源id 命名为R.drawable.logo,你可以用这个id指向(reference)图片资源以及将它插入你的用户界面。

提供resources与你的代码分离最为重要的一个方面是保证了提供可替换资源对不同设备配置进行适配的能力。例如,在xml中定义UI 字符串,你可以翻译这些字符串成其他语言然后在分离的文件中保存这些字符串。在语言限定词的基础之上,你可以添加资源目录名(像是res/values-fr/用于法文字符串的取值)以及用户语言的设置。Android系统使用适当的语言字符用于你的UI.

Android 提供很多不同的限定符用于你的可替换资源。限定符是一个简短的字符串,包含在你的资源目录命名中为了根据设备的配置来决定使用哪个资源。像在其他例子中,你应该为了你的activity创建不同layouts.依赖于设备的屏幕尺寸以及方向。举个例子,当屏幕的方向是竖屏时(in portrait oruentation),你可能想要layout的按钮是竖直的,但是当屏幕的方向是横屏时(in landscape orientation),按钮应该是横着的。依赖于方向来改变layout,你可以定义两种不同的layouts,通过限定符放在各自的layout目录中。然后,系统将自动的根据当前的设备方向来使用layout. 

 

 

posted @ 2013-10-28 21:23  Jsaint  阅读(592)  评论(0)    收藏  举报