本章目标:
熟悉Android应用程序四大组件。
4.1Android应用文件组成
Android应用程序由以下4个模块构造而成:
Activity
Intent
ContentProvider
Service
当然,也不是每个Android应用程序都必须由这4部分组成,它可以根据开发者需求来进行组合,比如上面建立的HelloAndroid项目就只使用了Activity这一个模块。但是,任何一个应用程序都必须在AndroidManfest.xml文件中声明使用到的这些模块。
4.1.1Activity
Activity是最基本的模块,我们在HelloAndroid项目中已经使用过。我们称之为"活动",在应用程序中,一个活动(Activity)通常就是一个单独的屏幕。每一个活动都被实现为一个独立的类,并且从活动基类中继承而来,活动类将会显示由视图控件组成的用户接口,并对事件作出响应。例如上HelloAndroid项目中的HelloAndroid.java即继承了活动(Activity)类。大多数的应用都是由多个Activity显示组成,例如,对一个文本信息应用而言,第一个屏幕用来显示发送消息的联系人列表,第二个屏幕用来写文本消息和选择收件人,第三个屏幕查看消息历史或者消息设置操作等。
这里的每一个屏幕就是一个活动,很容易实现从一个屏幕到一个新的屏幕,并且完成新的活动。当一个新的屏幕打开后,前一个屏幕将会暂停,并保存在历史栈中。用户可以返回到历史栈中的前一个屏幕,当屏幕不再使用时,还可以从历史栈中删除。
简单理解,Activity代表一个用户所能看到的屏幕,主要用于处理应用程序的整体性工作,例如,监听系统事件(按键事件、触摸屏事件等),为用户显示指定的View,启动其他Activity等。所有应用的Activity都继承于android.app.Activity类,该类是Android提供的基层类,其他的Activity继承该父类后,通过父类的方法来实现各种功能,这种设计在其他领域也较为常见。
Activity中常用的函数有SetContentView() findViewById() finish() startActivity(),其生命周期涉及的函数有:
voidonCreate(Bundle savedInstanceState)
void onStart()
voidonRestart()
void onResume()
void onPause()
voidonStop()
void onDestroy()
Activity的使用需要在Manifest文件中添加相应的<Activity>,并设置其属性和intent-filter。
4.1.2Intent& Boradcast Receiver
Android用Intent这个特殊类实现在Activity与Activity之间的切换。Intent类用于描述应用的功能。在Intent的描述结构中,有两个最重要的部分:动作和动作对应的数据。典型的动作类型有:MAIN、VIEW、PICK、EDIT等,而动作对应的数据则以URI的形式表示。例如,要查看一个人的联系方式,需要创建一个动作类型为VIEW的intent,以及一个表示这个人的URI。
通过解析各种intent,从一个屏幕导航到另一个屏幕是很简单的。当向前导航时,activity将会调用startActivity(IntentmyIntent)方法。然后,系统会在所有已安装的应用程序中定义的IntentFilter中查找,找到最匹配myIntent的Intent对应的activity。新的activity接收到myIntent的通知后,开始运行。当startActivity方法被调用时,将触发解析myIntent的动作,该机制提供了两个关键好处:
Activities能够重复利用从其他组件中以Intent的形式产生的请求。
Activities可以在任何时候被具有相同IntentFilter的新的Activity取代。
4.1.3Service
Service即"服务"的意思,既然是服务,那么Service将是一个生命周期长而且没有用户界面的程序。比如一个正在从播放列表中播放歌曲的媒体播放器,在这个媒体播放器应用中,应该会有多个activity,让使用者可以选择歌曲并播放歌曲。然而,音乐重放这个功能并没有对应的activity,因为使用者会认为在导航到其他屏幕时音乐应该还在播放。在这个例子中,媒体播放器这个activity会使用Context.startService()来启动一个service,从而可以在后台保持音乐的播放。同时,系统也将保持这个service一直执行,直到这个service运行结束。另外,我们还可以通过使用Context.bindService()方法连接到一个service上(如果这个service当前还没有处于启动状态,则将启动它)。当连接到一个service之后,还可用service提供的接口与它进行通讯。以媒体播放器为例,我们还可以执行暂停、重播等操作。
4.1.4Content Provider
Android应用能够将它们的数据保存到文件和SQLite数据库中,甚至是任何有效的设备中。当你想将你的应用数据与其他的应用共享时,ContentProvider就可以发挥作用了。因为ContentProvider类实现了一组标准的方法,能够让其他的应用保存或读取此内容提供器处理的各种数据类型。
数据是应用的核心。在Android中,默认使用鼎鼎大名的SQLite作为系统数据库。但是在Android中,使用方法有点小小的不一样。在Android中,每一个应用都运行在各自的进程中,当一个应用需要访问其他应用的数据时,也就是数据需要在不同的虚拟机之间传递,这样的情况操作起来可能有些困难(正常情况下,你不能读取其他应用的db文件),ContentProvider正是用来解决在不同的应用包之间共享数据的工具。
在Android中,contentprovider是一个特殊的存储数据的类型,它提供了一套标准的接口用来获取和操作数据。并且,Android自身也提供了现成的contentprovider:Contacts、Browser、CallLog、Settings、MediaStore。应用可以通过唯一的ContentResolverinterface来使用具体的某个contentprovider,然后你就可以用ContentResolver提供的方法来使用你需要的contentprovider了。其中,contentResolver提供的方法包括query()、insert()、update()等。要使用这些方法,还会涉及URI。你可以将它理解成string形式的contentProvider的完全路径。
4.2Android应用项目文件组成
4.2.2R.java
R.java是在建立项目时自动生成的,这个文件是只读模式,不能更改,R.java文件是定义该项目所有资源的索引文件。先来看看项目中一个典型的R.java文件。
package com.imti.helloworld.HelloWorld; public final class R { public static final class attr { } public static final class drawable { public static final int icon=0x7f020000; } public static final class layout { public static final int main=0x7f030000; } public static final class string { public static final int app_name=0x7f040001; public static final int hello=0x7f040000; } } |
可以看到这里定义了很多常量,仔细一看就发现这些常量的名字都与res文件夹中的文件名相同,这再次证明R.java文件中所存储的是该项目所有资源的索引。有了这个文件,在程序中使用资源将变得更加方便,可以很快地找到要使用的资源,由于这个文件不能被手动编辑,所以当我们在项目中加入了新的资源时,只需要刷新一下该项目,R.java文件便自动生成了所有资源的索引。
4.2.1AndroidManifest.xml
AndroidManifest.xml主要包含以下功能:
1) 说明application的java数据包,数据包名是application的唯一标识; 2) 描述application的component; 3)说明application的component运行在哪个process下; 4)声明application所必须具备的权限,用以访问受保护的部分API,以及与其他application的交互; 5)声明application其他的必备权限,用以component之间的交互; 6)列举application运行时需要的环境配置信息,这些声明信息只在程序开发和测试时存在,发布前将被删除; 7) 声明application所需要的AndroidAPI的最低版本级别,比如1.0,1.1,1.5; 8) 列举application所需要链接的库; |
AndroidManifest.xml文件的结构、元素,以及元素的属性,可以在AndroidSDK文档中查看详细说明。而在看这些众多的元素以及元素的属性前,需要先了解一下这些元素在命名、结构等方面的规则:
1)元素:在所有的元素中只有<manifest>和<application>是必需的,且只能出现一次。如果一个元素包含有其他子元素,必须通过子元素的属性来设置其值。处于同一层次的元素,这些元素的说明是没有顺序的。 2)属性:按照常理,所有的属性都是可选的,但是有些属性是必须设置的。那些真正可选的属性,即使不存在,其也有默认的数值项说明。除了根元素<manifest>的属性,所有其他元素属性的名字都是以android:前缀的; 3)定义类名:所有的元素名都对应其在SDK中的类名,如果你自己定义类名,必须包含类的数据包名,如果类与application处于同一数据包中,可以直接简写为“.”; 4)多数值项:如果某个元素有超过一个数值,这个元素必须通过重复的方式来说明其某个属性具有多个数值项,且不能将多个数值项一次性说明在一个属性中; 5)资源项说明:当需要引用某个资源时,其采用如下格式:@[package:]type:name。例如<activity android:icon=”@drawable/icon ” . . . > 6) 字符串值:类似于其他语言,如果字符中包含有字符“\”,则必须使用转义字符“\\”; |
实例说明AndroidManifest.xml文件:
<?xml version=”1.0″encoding=”utf-8″?> <manifestxmlns:android=”http://schemas.android.com/apk/res/android” package=”moandroid.flashlight” android:versionCode=”1″ android:versionName=”1.0″> <applicationandroid:icon=”@drawable/icon”android:label=”@string/app_name”> <activityandroid:name=”.flashlight” android:label=”@string/app_name”> <intent-filter> <actionandroid:name=”android.intent.action.MAIN” /> <categoryandroid:name=”android.intent.category.LAUNCHER” /> </intent-filter> </activity> </application> <uses-sdkandroid:minSdkVersion=”7″ /> </manifest> |
1)除去头部XML信息说明,首先是manifest项—根节点,其属性包括:schemasURL地址、包名(moandroid.flashlight),以及程序的版本说明。
2)其次是manifest的子节点application,其属性包括:程序图标、程序名称。前面带有@表示引用资源,例如:@drawable/icon表示引用的是drawable资源中的icon,可以在其源工程的res/drawable中找到。
3)然后就是application的子节点activity,其属性包括:activity的名称、activity的标签名,其子节点intent-filter则是对activity的说明。
4)而在intent-filter中,actionandroid:name=”android.intent.action.MAIN”和categoryandroid:name=”android.intent.category.LAUNCHER”用以说明程序启动时的入口activity是哪个。如果这两个属性值中分别含有MAIN和LAUNCHER,则说明它就是启动程序时的入口活动。
5) uses-sdkandroid:minSdkVersion=”7″说明程序使用的AndroidSDK的最低版本,其中1表示Android1.0,2表示Android1.1,而3则表示Android1.5。
在Eclipse中创建工程后,会自动生成一个AndroidManifest.xml文件。在代码编写的过程中,需要同时修改AndroidManifest.xml,如果配置出现错误会导致程序不能正常运行。
manifest | 根节点,描述了package中所有的内容 |
xmlns:android | 包含命名空间的声明。 xmlns:android=http://schemas. android.com/apk/res/android,使得 Android中各种标准属性能在文件中使用, 提供了大部分元素中的数据 |
Package | 声明应用程序包 |
application | 包含package中application级别组件声 明的根节点。此元素也可包含application 的一些全局和默认的属性,如标签、icon、 主题、必要的权限,等等。一个manifest 能包含零个或一个此元素(不能大余一个) |
android:icon | 应用程序图标 |
android:label | 应用程序名字 |
Activity | 用来与用户交互的主要工具。Activity是用 户打开一个应用程序的初始页面,大部分 被使用到的其他页面也由不同的activity所 实现,并声明在另外的activity标记中。 注意,每一个activity必须有一个<activity> 标记对应,无论它给外部使用或是只用于 自己的package中。如果一个activity没有 对应的标记,你将不能运行它。另外, 为了支持运行时查找Activity,可包含一个 或多个<intent-filter>元素来描述activity所支持的操作 |
android:name | 应用程序默认启动的activity |
intent-filter | 声明了指定的一组组件支持的Intent值,从 而形成了IntentFilter。除了能在此元素下指 定不同类型的值,属性也能放在这里来描 述一个操作所需的唯一的标签、icon和其他信息 |
action | 组件支持的Intentaction |
category | 组件支持的IntentCategory。这里指定 了应用程序默认启动的activity |
uses-sdk | 该应用程序所使用的sdk版本相关 |
AndroidManifest.xml功能表
4.2.2main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/login" /> <EditText android:id="@+id/etUserName" android:layout_weight="1.0" android:maxLength="8" android:maxLines="1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" /> </LinearLayout> |
1)<?xml version="1.0" encoding="utf-8"?> xml标记描述语言,必须的。
2)<LinearLayout> 线性版面配置,在这个标签中,所有元件都是按由上到下的排队排列。
3)xmlns:android=http://schemas.android.com/apk/res/android描述xml描述档案的名称空间。必须属性
4)android:orientation="vertical"表示这个介质的版面配置方式是从上到下的垂直得排列其内部的视图android:orientation="horizontal" 水平排列
5)android:layout_width="fill_parent"定义当前视图在屏幕上可以消费的宽度,fill_parent即填充整个屏幕。android:layout_height="fill_parent" "wrap_content":随着文字栏位的不同而改变这个视图的宽度或者高度。有点自动设置框度或者高度的意思
6)android:layout_weight="1.0"
Layout_weight属性是为了要EditText能延伸到最右侧,用于给一个线性布局中的诸多视图的重要度赋值。所有的视图都有一个layout_weight值,默认为零,意思是需要显示多大的视图就占据多大的屏幕空间。若赋一个高于零的值,则将父视图中的可用空间分割,分割大小具体取决于每一个视图的layout_weight值以及该值在当前屏幕布局的整体 layout_weight值和在其它视图屏幕布局的layout_weight值中所占的比率而定。
举个例子:比如说我们在水平方向上有一个文本标签和两个文本编辑元素。该文本标签并无指定layout_weight值,所以它将占据需要提供的最少空间。如果两个文本编辑元素每一个的layout_weight值都设置为1,则两者平分在父视图布局剩余的宽度(因为我们声明这两者的重要度相等)。如果两个文本编辑元素其中第一个的layout_weight值设置为1,而第二个的设置为2,则剩余空间的三分之一分给第一个,三分之二分给第二个(因为我们声明第二个有较之第一个更高的重要度)。
在本例中,一个水平方向上的线性布局嵌套在另一垂直方向上的布局中,以使标题标签和文本字段在水平方向上挨个对齐,这里的Layout_weight属性是为了要两个Button的宽度相等,同时又能填充满一行。因为1.0 :1.0== 1:1. 所以宽度相等了.
4.3Android常用开发术语
1) apk扩展名
apk是Android包的扩展名,一个Android包包含了与某个Android应用程序相关的所有文件,apk文件将AndroidManifest.xml文件、应用程序代码(dex文件)、资源文件和其他文件组成一个压缩包,一个项目只能打包压缩成一个apk文件。
2)dex扩展名
Android的程序被编译成.dex(DalvikExecutable)格式文件,然后再进行打包生成可被直接安装的apk文件。
3)应用程序(APP)
一个或多个Activity、服务、监听和Intent接收器的集合,一个应用程序有一个文件清单,并且打包成一个apk文件。
4) Action
对Intent发送器意图的描述,一个活动是一个指派给Intent的字符串值。活动字符串可以由Android定义,也可以由第三方开发者定义。例如,在网页URL中使用的android.intent.action.VIEW或者在用户应用程序中使用的com.example.rumbler.SHAKE_PHONE来使电话震动。
5) ADB(Android Debug Bridge )
SDK自带的一个基于命令行的调试程序。它提供了设备浏览工具、设备上的拷贝工具和为调试转寄端口的功能。更多信息请参考附录三(Android的ADB工具使用)。
6) 内容源
内容源是建立在类ContentProvider之上的用于处理指定格式的内容请求字符串,并返回指定格式的数据的类。关于内容源的使用信息请参考本书第7章内容。
7) DalvikAndroid
虚拟机的名字,Dalvik虚拟机是一个只能解释执行dex文件的虚拟机,dex文件针对存储性能和内存管理进行了优化。Dalvik虚拟机是基于寄存器的虚拟机,并且能够运行经过Dalvik自带的“dx”工具转换过的Java类。虚拟机运行在兼容Posix的操作系统上,依赖于底层的功能(如线程和低级内存管理)。Dalvik的核心类库有意做得与Java标准版非常类似,但它明显更适合小型移动设备。
8)DDMS
调试监视服务(DalvikDebug Monitor ServiceDalvik)是SDK自带的一个可视的调试工具。它提供了屏幕捕捉、日志存储和进程检测能力。
9)Drawable
编译过的可视化资源,可以用来做背景、标题或屏幕的其他部分。它被编译在android.graphics.drawable子类中。
10)意图(Intent)
意图是一个Intent类,它包含很多描述调用者意图做什么的字段。调用者发送意图到Android意图处理器,意图处理器会遍历所有应用程序的意图过滤器来查找与该意图最匹配的Activity。意图字段包括渴望的动作、种类、数据、数据的MIME类型、一个处理类和其他约束。
11)意图过滤器(intent-filter)
Activity和意图接收器(Receiver)在它们的文件清单中包含一个或多个过滤器,用来描述什么类型的意图或者信息是它们能处理或想接收的。一个意图过滤器列出了一系列要求,例如,意图或信息必须满足的数据类型、被请求的动作和URI的格式。对于Activity,Android搜索意图和Activity过滤器匹配程度最高的Activity;对于消息,Android会将消息转发给所有匹配意图过滤器的接收器。
12)Intent接收器(Receiver)
一个监听是由Context.broadcastIntent()发出的信息广播的类,详细信息请参考本书第9章。
13)布局资源
一个描述Activity屏幕布局的XML文件。
14)文件清单
应用程序中的一个XML文件,用于描述包中多个Activity、Intent过滤器、服务和其他内容。可以打开AndroidManifest.xml查看其包含的内容。
15)Nine-patch / 9-patch / Ninepatch image
一种可变尺寸的位图资源,可用作设备上的背景或其他图片。
16)资源
用户提供的XML、位图或其他文件,构建程序时会导入进来,稍后会被代码加载,Android支持多种类型的资源,请参考Resources中的详细描述,程序定义的资源文件应当保存在res/子目录下。
17)服务(Service)
运行在后台执行多种固定任务的类,如播放音乐或检测网络活动。
18)主题(Theme)
一系列定义多种默认显示设置的参数(文字大小、背景颜色等)。Android在R.style中提供了几个标准的主题(以"Theme_"开头)。
19)URIs
Android使用URI字符串请求数据(如通信录列表)和动作(如在浏览器中打开网页)。URI字符串可以具有不同的格式。所有请求数据的URI必须以“content://”开头。有效的动作URI字符串会被设备上的适当的程序处理,例如,以“http://”开头的URI字符串会被浏览器处理。
4.4小结
本章介绍了Android应用程序主要四大组成部分和Android应用项目文件组成,通过本章学习对Android应用结构有初步认识.
4.5练习
1. 请详细描述Android应用文件组成?
2. 简述Android应用项目文件组成?