1
安卓应用开发案例教程
1.6.3.1 3.3.1 Activity
3.3.1 Activity

在现实生活中,人们经常会使用手机打电话、发短信、玩游戏等,这就需要与手机界面进行交互。在Android系统中,用户和程序的交互是通过Activity完成的,Activity负责管理Android应用程序的用户界面。

Activity是Android应用程序四大模块中最基本的模块,人们称之为“活动”。Activity是最容易吸引用户的模块,它是一种可以包含用户界面的组件,主要用于和用户进行交互。在应用程序中,一个Activity通常就是一个单独的屏幕。这里的每一个屏幕就是一个Activity。

其实在上一章中已经简要介绍过Activity,读者对Activity也有了初步的认识。但是,到目前为止,还没有手动创建过Activity,因为上一章中的MainActivity是ADT自动创建的。下面手动创建一个Activity。

1.手动创建一个Activity

首先需要新建一个Android项目,项目名称设定为“ActivityDemo”,包名使用默认值“com.example.activitydemo”。新建项目的步骤已经在上一章介绍过,不过图2-18所示的步骤要进行修改,不再勾选“Create Activity”复选框,因为需要手动创建Activity,如图3-3所示。

图3-3 “Create Activity”界面

单击“Finish”按钮,项目就创建完成了。此时Eclipse中存在两个项目——“ActivityDemo”和“HelloWorld”,为了避免以后出现不必要的麻烦,先把不相干的“HelloWorld”项目关闭,用鼠标右键单击“HelloWorld”项目,然后选择“Close Project” 命令即可。

目前“ActivityDemo”项目的src目录是空的,先在src目录下添加一个包。在Eclipse的Package Explorer中,用鼠标右键单击“ActivityDemo”项目,选择src目录,在弹出的菜单中选择“New”→“Package”选项,然后在弹出窗口中的“Name”框中输入默认包名“com.example.activitydemo”,然后单击“Finish”按钮。添加包之后的目录结构如图3-4所示。

图3-4 添加包之后的目录结构

现在用鼠标右键单击“com.example.activitydemo” 包,在弹出的菜单中选择“New”→“Class”选项,此时会弹出新建类的窗口,在“Name”框中输入类名“FistActivity”,并让它继承自android.app.Activity,最后单击“Finish”按钮完成Activity的创建。

此时FirstActivity内部什么代码都没有,所以要先重写Activity中的onCreate()方法,代码如图3-5所示。

图3-5 onCreate()方法

从图中可以看到,onCreate()方法非常简单,就是调用了父类的onCreate()方法。这只是默认的实现方式,以后还需要往里面加入很多代码才可以实现需要的功能。

2.创建并加载布局

Android程序的开发采用的是MVC框架,讲究的是逻辑和视图分离,因此每个Activity最好都能对应一个布局,布局用来显示界面内容,因此现在来手动创建一个布局文件。

在Eclipse的Package Explorer中,用鼠标右键单击res→layout目录,在弹出的菜单中选择“New”→“Other”→“Android XML Layout File”选项,在弹出的创建布局文件窗口中将布局文件命名为“first_layout”,根元素默认选择“LinearLayout”,如图3-6所示。

单击“Finish”按钮完成布局的创建。这时会看到图3-7所示窗口。

上图是ADT自动创建的布局文件,并且提供可视化布局编辑器,在屏幕的中间位置可以预览当前的布局。可以通过拖拽左侧控件的方式编辑布局,也可以通过XML文件的方式编辑布局。在图3-7所示窗口的最下方有两个标签,一个是“Graphical Layout”,就是当前的可视化布局编辑器,另一个是“first_layout.xml”。单击“first_layout.xml”标签,可以看到如下代码:

图3-6 “New Android Layout XML File”

图3-7 可视化布局编辑器

在创建布局文件的时候选择LinearLayout作为根元素,因此布局文件中已经有了一个LinearLayout元素。现在对这个布局进行编辑,添加一个按钮元素,代码如下:

这里在按钮元素的内部增加了几个属性。“android:id”是定义一个元素的唯一标识符,以后可以靠它在代码中对这个元素进行操作。“android:layout_width”指定了当前元素的宽度,这里使用match_parent表示让当前元素和父元素一样宽;“android:layout_height”指定了当前元素的高度,这里使用wrap_content表示当前元素的高度刚好包含里面的内容即可;“android:text”指定了元素中显示的文字内容。在后面的章节中针对布局的编写还会进行详细的介绍。接下来回到“Graphical Layout”标签,预览刚刚编辑的布局,如图3-8所示。

在屏幕中央的预览区,按钮已经成功显示出来,一个简单的布局已经编写完成了。接下来需要在Activity中加载这个布局。

在Eclipse中返回FirstActivity,在onCreate()方法中加入如下代码:

图3-8 添加按钮元素后的可视化布局编辑器

从代码里可以看到,在onCreate()方法中调用setContentView()方法给当前的Activity加载一个布局,而这个方法的参数一般都会传入一个布局文件的id。之前的章节已经作过介绍,项目中添加的任何资源都会在“R.java”文件中生成一个相应的资源id,因此只需要调用R.layout.first_layout就可以得到 “first_layout.xml”布局的id,最后将这个值传入setContentView()方法即可。

3.在AndroidM anifest文件中注册

前面提过,所有Activity都需要在“AndroidManifest.xml”文件中进行注册才能生效,所以现在就打开“AndroidManifest.xml”给刚刚新建的FirstActivity注册,具体代码如下:

Activity的注册声明需要放在<application>标签内,然后通过<activity>标签对Activity进行注册。首先使用android:name指定具体注册的是哪一个Activity,这里“.FirstActivity” 与com.example.activitydemo.FirstActivity具有一样的效果。这里使用“.FirstActivity”是因为最外层的<manifest>标签中已经通过package属性指定了程序的包名是“com.example.activitydemo.FirstActivity”,因此在注册Activity时这一部分就可以省略了,直接用“.FirstActivity”即可。使用android:label指定活动的标题栏的内容,标题栏是显示在活动最顶部的。在<activity>标签的内部加入了<intent-filter>标签,并在这个标签里添加了“<action android:name="android.intent.action.MAIN"/>”和“<category android:name="android.intent.category.LAUNCHER"/>”这两个声明。如果想让FirstActivity作为程序的主Activity,就是点击桌面应用程序图标时首先打开的就是这个Activity,那就必须加入这两句声明。

4.Activity的启动模式

通过前面的学习可以发现,Activity是可以层叠摆放的,每启动一个新的Activity,它就会覆盖在原Activity之上,如果单击“返回”按钮,则最上面的Activity被销毁,下面的Activity重新显示。Ativity之所以能这样显示,是因为Android系统是通过任务栈的方式来管理Activity实例的。

1)Android系统中的任务栈

栈是一种“先进后出”的数据结构。Android系统采用任务栈的形式来管理Activity。所谓的任务栈,是使用栈的方式来管理任务中的Activity,这个栈又称为回退堆栈,栈中Activity的顺序就是按照它们被打开的顺序依次存放的。

通常一个应用程序对应一个任务栈,默认情况下每启动一个Activity其都会入栈,并处于栈顶位置,用户操作的永远是栈顶的Activity。在栈中的Activity只有压入和弹出两种操作,被当前Activity启动时压入,用户单击“返回”按钮离开时弹出,而栈中Activity的位置和顺序都不会发生变化。无论开启多少个Activity,最后开启的Activity都会被压入栈的顶端并且获得焦点,而之前开启的Activity仍然保存在栈中,但已经被停止了。

2)Activity的4种启动模式

在实际开发中,应根据特定的需求为每个Activity指定恰当的启动模式。Activity的启动模式有4种,分别是standard、singleTop、singleTask和singleInstance。在“AndroidManifest.xml”文件中,通过<activity>标签的android:launchMode属性可以设置启动模式。下面对这4种启动模式进行详细讲解。

(1)standard模式。

standard模式是标准模式,也是Activity的默认启动模式,如图3-9所示。在这种模式下启动的Activity可以被多次实例化,即在同一个任务中可以存在多个Activity的实例,每个实例都会处理一个Intent对象。如果Activity A的启动模式为standard,并且Activity A已经启动,在Activity A中再次启动Activity A,会在Activity A的上面再次启动一个Activity A的实例。实际开发中,闹钟程序通常采用这种模式。

(2)singleTop模式。

在某些情况下,使用standard模式并不合理,例如当Activity已经位于栈顶,而再次启动Activity时还需创建一个新的实例,不能直接复用。在这种情况下,使用singleTop(图3-10)模式启动Activity更合理,该模式会判断要启动的Activity实例是否位于栈顶,如果位于栈顶则直接复用,否则创建新的实例,并且会调用该实例的onNew Intent()方法将Intent对象传递到这个实例中。在实际开发中,浏览器的书签通常采用这种模式。

(3)singleTask模式。

图3-9 standard模式

图3-10 singleTop模式

使用singleTop模式虽然可以很好地解决重复创建栈顶问题,但如果Activity并未处于栈顶位置,则可能还会创建多个实例。如果想要某个Activity在整个应用程序中只有一个实例,则需要借助singleTask模式来实现,如图3-11所示。当Activity的启动模式指定为singeTask时,则每次启动该Activity时,系统首先会检查栈中是否存在当前Activity实例,如果存在,则直接使用,并把当前Activity之上的所有实例全部出栈,否则会重新创建一个实例。在实际开发中,浏览器主界面通常采用这种模式。

(4)singleInstance模式。

singlelnstance模式是4种启动模式中最特殊的一个(图3-12),指定为singlelnstance模式的Activity会启动一个新的任务栈来管理Activity实例,无论从哪个任务栈中启动该Activity,该实例在整个系统中只有一个。这种模式存在的意义,是为了在不同程序中共享同一个Activity实例。

图3-11 singleTask模式

Activity采用singleInstance模式启动分两种情况:一种是要启动的Activity不存在,则系统会先创建一个新的任务栈,然后创建Activity实例;一种是要启动的Activity已存在,无论当前Activity位于哪个程序的哪个任务栈中,系统都会把Activity所在的任务栈转移到前台,从而使Activity显示。在实际开发中,来电界面通常采用这种模式。

图3-12 singleInstance模式

在实际开发中,根据实际情况选择合适的启动模式即可。

现在运行程序,运行结果如图3-13所示。

在界面的最顶部是一个标题栏,上面显示的是刚才在注册Activity时指定的内容。标题栏下方就是布局文件中编写的界面,可以看到刚刚定义的TextView控件。