本节书摘来自异步社区《Android开发秘籍(第2版)》一书中的第2章,第2.1节Android应用程序概览,作者 【美】Ronan Schwarz , Phil Dutson , James Steele , Nelson To,更多章节内容可以访问云栖社区“异步社区”公众号查看
2.1 Android应用程序概览
Android开发秘籍(第2版)
Android应用程序包含的功能五花八门,比如编辑文本、播放音乐、启动闹钟或是打开通讯录等。这些功能可以被分类对应到4类Android组件之中,如表2-1所示,每一类都对应一个Java基本类。
每个应用程序都由一个或多个这样的组件组成。当要用到某个组件时,Android操作系统就会将其初始化。其他应用程序在指定的权限内也可以使用它们。
随着在操作系统中展现多种功能(有些功能甚至与预期的应用程序无关,如呼入电话),每个组件经历了生命周期的创建(create)、聚焦(focus)、失去焦点(defocus)和销毁(destroy)过程。对于优雅的操作(比如保存变量或者恢复用户界面元素)可以重写其默认行为,使交互对用户更加友好。
除了ContenProvider组件,每个组件都需要一个叫做Intent的异步消息来激活。Intent可包含一组(Bundle)描述该组件的辅助数据。这也提供了一种在组件之间传递消息的方法。
本章最后将使用最常见的组件Activity演示前面提到的概念。由于Activity总是和具体的用户交互相关,所以每个Activity在创建时会自动创建一个新窗口。当然还会提到一些关于UI的概要介绍。至于Service和BroadcastReceiver这两个组件我们将会在第3章中讲解,而ContentProvider则会在第11章中阐述。
技巧1:创建项目和Activity
创建Android项目或其组件最直截了当的方式,当属使用Eclipse集成开发环境(IDE)。这样做可以确保所有辅助文件被正确安装。用Eclipse新建Android项目的步骤具体如下。
(1)在Eclipse下,选择File → New → Android Application Project,这样会出现新建Android项目的界面。
(2)填写项目名称,比如SimpleActivityExample。
(3)填写应用程序的名称,比如Example of Basic Activity。
(4)填写包名称,例如com.cookbook.simpleactivity。
(5)选择SDK的最低要求,这将成为可以运行应用的最低Android版本。建议最低选择API Level 8或Android 2.2。
(6)从给出的选项中选择构建程序的目标SDK版本,此处应选择测试应用时会用到的最高Android版本。
(7)选择用于编译应用的SDK版本,这里应选择可用的最新版本,或者要用到的库所需的最低版本。
(8)选择应用程序的基本主题(theme)。以后还可以按需修改主题,不过在此早些指定一个没有坏处。
(9)接下来,设置另一些项目默认参数。选中Create custom launcher icon一项,以替换当前的默认图标。要在后面的步骤中创建主Activity,请确保你勾选了Create Activity项。
(10)在Configure Launcher Icon界面,可以在文本、一小组剪贴画或磁盘中的图片里面选定应用的图标。系统会基于选定的图像,分别创建符合4种标准分辨率的图标。
(11)要在同一步骤中创建主Activity,应确保勾选了Create Activity项,并选择BlankActivity选项。Fragment的使用将在后面的技巧中予以介绍。
(12)填写Activity和布局的名字,或者维持默认值。要使用默认导航模式中的某一个,需要SDK版本为14或更高才行,因为这有赖于ActionBar的支持。
(13)点击Finish按钮完成这一实例工程的创建。
所有的Activity均继承了抽象类Activity或它的一个子类。每个Activity的入口为onCreate()方法。通常为初始化Activity,都会对该方法进行重写,以完成设置UI、创建按钮监听器(listener)、初始化参数,或是启动线程一类的工作。
如果主Activity并未随项目一起创建,或者需要另行创建一个Activity,那么可以采取以下步骤。
(1)创建一个继承Activity类的新类。在Eclipse下可以这样做:在项目上右击,选择New → Class,然后指定android.app.Activity作为父类。
(2)重写onCreate()函数。在Eclipse下可这样做:在类文件上右击,选择Source → Override/ImplementMethods...,然后选中onCreate()方法。同大多数重写函数一样,重写onCreate()方法需要调用父类的该方法,如若不然,可能在运行时抛出异常。在此,应当首先调用super.onCreate()方法,以确保Activity的正确初始化,如代码清单2-1所示。
代码清单2-1 src/com/cookbook/simple_activity/SimpleActivity.java
package com.cookbook.simple_activity;
import android.app.Activity;
import android.os.Bundle;
public class SimpleActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
(3)如果要用到UI,需在res/layout/目录下的一个XML文件中指定布局。此处该文件称为main.xml,如代码清单2-2所示。
代码清单2-2 res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
</LinearLayout>
(4)使用setContentView()函数设置Activity的布局,并将XML布局文件对应的资源ID作为参数传递给它。此处该参数为R.layout.main,已显示在代码清单2-1中。
(5)在AndroidManifest.xml文件中声明Activity的属性,详细内容会在稍后的代码清单2-5中涵盖。
注意,字符串类型资源均在res/values文件夹下的strings.xml中定义,如代码清单2-3所示。该文件为需要被修改或重用的字符串提供了一个集结地。
代码清单2-3 res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, SimpleActivity!</string>
<string name="app_name">SimpleActivity</string>
</resources>
下面要对项目的结构及其他一些自动生成的内容进行详细探究。
2.1.1 项目目录结构及自动生成的内容
项目结构是用户生成的文件与自动生成文件的混合体。图2-1给出了Eclipse Package Explorer(Eclipse包浏览器)中显示的项目结构的一个示例。
用户生成的文件包括以下这些。
src/目录包含了用户为应用编写或导入的Java包。每个包可以包含多个.java文件,分别代表不同的类。
res/layout/下包含了为每一屏界面指定布局的XML文件。
res/values/下含有被其他文件所引用的XML文件。
res/values-v11/用于存放Honeycomb1及更高版本设备使用的XML文件。
res/values-v14/用于存放Ice Cream Sandwich2及以上版本设备使用的XML文件。
res/drawable-xhdpi/、res/drawable-hdpi/、res/drawable-mdpi/和res/drawable-ldpi/分别包含应用在极高、高、中、低每英寸点数分辨率下所用的图片。
assets/下存有应用要用到的非媒体文件。
AndroidManifest.xml用于向Android系统指定该项目的特性。
每个名为res/values-XX的文件夹下均生成有styles.xml。这是因为Android基本主题从Honeycomb版本起变为了Holo,这导致应用的主题拥有不同的父主题。
自动生成的文件则有以下这些。
gen/之下包含了自动产生的代码,包括生成的类文件R.java。
project.properties里含有项目设定。尽管是自动生成的,它也应当被纳入版本控制之下。
应用程序的资源包括描述布局的XML文件、定义包括如字符串和UI元素标签等的各种值的XML文件,以及其他支持文件,比如图片和声音。编译时,对资源的引用都会收集到一个名为R.java的自动生成的包装类(wrapper class)中。Android Asset打包工具会自动生成该文件。代码清单2-4给出了技巧1的项目产生的R.java的内容。
代码清单2-4 gen/com/cookbook/simple_activity/R.java
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.cookbook.simple_activity;
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;
}
}
在这里,每个资源都被映射到一个独一无二的整型(integer)值。通过这种方式,R.java类提供了一种在Java代码中引用外部资源的办法。例如,要在Java中引用main.xml,就使用整型值R.layout.main。而要在XML文件里引用该资源,则应使用“@layout/main”字符串。
表2-2展示了在Java或XML文件中引用资源的方法。注意,要定义一个ID名为home_button的新按钮,需要在其标识字符串前面加上一个加号,就像这样:“@+id/home_button”。关于资源更完整的细节请见第5章,此处介绍的内容对于学习本章的技巧已经足够。
2.1.2 Android包和manifest文件
Android项目,有时也被称为Android包,乃是Java包的集合。不同的Android包可以拥有相同的Java包名,但Android设备上安装的每个Android包的名字都应当是独一无二的。
为让操作系统访问这些包,每个应用程序必须在一个名为AndroidManifest.xml文件中声明它所有可用的组件。此外,该文件还包含运行应用所需的权限和行为。代码清单2-5给出了技巧1对应的AndroidManifest.xml的内容。
代码清单2-5 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cookbook.simple_activity"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon"
android:label="@string/app_name">
<activity android:name=".SimpleActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="8" />
</manifest>
第一行对于Android中的所有XML文件都是标准的和必须的,用于指定编码。manifest元素定义了Android包的名字和版本。versionCode是一个整型值,可在程序中对其求值,以确定版本的高低关系。versionName以人们可读懂的格式表示了声明的主版本号和子版本号。
application元素定义了用户会在Android设备菜单中看到的应用程序的图标和标签。标签是一个字符串,应当足够简短,以便在用户设备中正确显示在图标下方。通常,该名字最长为两个单词,每个单词由10个连续的英文字符构成。
activity元素定义了应用启动时调用的主Activity,以及Activity活动时标题栏(title bar)中显示的名称。在此需要给Java包指定名字,本例中为com.cookbook.simple_activity.
SimpleActivity。由于Java包名通常与Android包名相同,常常使用简化形式.Simple-
Activity。然而,最好记得Android包和Java包还是有区别的。
intent-filter元素向Android系统说明组件的功能,为此,它可以包含多个action、category或data元素。该元素在本书的许多技巧中都会用到。
uses-sdk元素定义了运行应用所需的API级别。一般来说,API级别会像下面那样指定:
<uses-sdk android:minSdkVersion="integer"
android:targetSdkVersion="integer"
android:maxSdkVersion="integer" />
由于Android系统按向前兼容原则构建,强烈不推荐使用maxSdkVersion参数(在Android 2.0.1及以后版本中它已经被剔除掉了)。然而Google Play仍然在使用它作为一个过滤参数,在运行大于这一参数的SDK版本的设备上,该应用程序就会被显示为不可下载。
targetSdkVersion并非必须指定,但指定它可以让拥有相同SDK版本的设备关闭兼容性设置,这可能会提升操作速度。应该始终指定minSdkVersion的值,以确保一个应用运行在不支持其所需特性的平台上时不会崩溃。在指定该值时应总是选择可能的最低API级别。
AndroidManifest.xml文件还可以包含运行该应用所需的权限设定。后面的章节会给出关于所提供选项的更完整介绍,以上所讲对于本章的技巧来说已经够用了。
技巧2:重命名应用程序的某些部分
有时候Android项目的某部分需要被重命名。也许有某个文件被(比如从本书中)手动复制进了项目。也许应用程序在开发期间改了名,也需要在文件系统树上反映出来。这项工作由自动化工具协助我们完成,同时确保那些交叉引用也被自动更新。例如,在Eclipse IDE里,有多种办法实现对应用程序某一部分的重命名。
要重命名Android项目,步骤如下。
(1)在项目上右击,选择Refactor → Move将其移动到文件系统中的一个新目录中。
(2)在项目上右击,选择Refactor → Rename重命名项目。
要重命名Android包,步骤如下。
(1)在包上右击,选择Refactor → Rename重命名包。
(2)编辑AndroidManifest.xml文件,确保新的包名在其中得到反映。
要重命名Android类(比如像Activity、Service、BroadCastReceiver和ContentProvider这样的主要组件),步骤如下。
(1)在.java文件上右击,选择Refactor → Rename重命名类。
(2)编辑AndroidManifest.xml文件,确保android:name之下的名字得到更新。
注意,重命名其他文件,诸如XML文件,通常需要手动更改Java代码中相应的引用。
技巧3:使用库项目
库项目(library project)允许资源和代码在其他应用程序中被复用,它们也被用作UI库以使较老的设备能支持新的特性。库项目在SDK工具版本14中被首次引入。库项目与一般的Android项目很类似,同样包含源码、资源文件夹和manifest文件。二者主要的区别在于库项目不能独立运行,且无法被编译成.apk文件。创建库项目的步骤如下。
(1)在Eclipse下,选择File → New → Android Application Project,这样会出现新Android项目的创建界面。
(2)填写项目名称,比如SimpleLibraryExample。
(3)填写应用程序的名称,比如Example of Basic Activity。
(4)填写包名称,例如com.cookbook.simplelibrary。
(5)从给出的选项中选择构建程序的目标SDK版本,这些选项基于开发机上已安装的SDK版本而提供。
(6)取消勾选Create custom launcher icon一项,因为库不需要图标。
(7)勾选Mark this project as a Library一项。
(8)要在库中包含Activity,应选中Create Activity项。此处创建的Activity会在主项目中用到,目前勾选上Create Activity并选择BlankActivity即可。
(9)填写活动名称,或者维持默认。
(10)把布局名改为lib activity main。由于所有资源最终都会被编译进单个R类文件中,最好给库的所有资源起一个统一的前缀,以避免命名冲突。
(11)点击Finish按钮完成库项目的创建。
要使用该库,需要一个主项目。依照技巧1的方法为工作区添加一个新项目,只需要进行一点微小的改动,即不需为该项目创建Activity,取而代之地,使用之前创建的库项目中的Activity。
要在主项目中引用库项目,操作如下。
(1)在Eclipse里右击项目并选择Properties → Android。
(2)向下滚动到库部分,并点击Add。
(3)会弹出一个对话框,显示工作区内所有可用的库项目,从中选择SimpleLibrary并按下OK按钮。
现在项目名称和引用路径已显示在Properties页中,会有一个绿箭头表明引用通过了检查。如果找不到引用路径,则会显示一个红叉。
添加了库项目后,建议对工作区做一次干净而完全的构建操作,以确保我们所做的变更能按预期工作。
在内部,库引用被保存在project.properties文件中,该文件同时为Eclipse和Ant所用。该文件内容应该像下面这样:
target=android-16
android.library.reference.1=../SimpleLibrary
代码清单2-6将库中的Activity添加到AndroidManifest.xml文件里,并将其设为默认启动的Activity。
代码清单2-6 主项目的AndroidManifest.xml
<manifest xmlns:android="[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"
package="com.example.simpleproject"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" />
<application android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:theme="@style/AppTheme">
<activity
android:name="com.cookbook.simplelibrary.LibMainActivity"
android:label="@string/title_activity_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
在此注意,应用程序的包名与Activity的名字截然不同,由于Activity是从库项目中调用的,为其设定的名称必须是完全合格的包名和类名。
现在项目可以在Eclipse中运行了,库中的Activity会在前台显示。
库项目有很多用途,从为主项目设置不同主题、但运行在相同基础代码之上的white-label3应用,到使用像ActionBarSherlock这样的UI库为老Android设备带来新的外观和感觉。
1Honeycomb为Android 3.0~3.2版的别名,这里特指对应API Level 11的3.0版本。——译者注
2Ice Cream Sandwich为Android 4.0版的别名,对应API Level 14。——译者注
3所谓white-label是这样一类产品和服务,它们由一家公司(制造商)生产,但其他公司(市场商)可以对其进行重塑,让它们以自己的面貌面世。——译者注