第5章
Activity 

Activity是与用户交互的接口,提供了图形界面供用户操作。前文中每个应用程序
都用到了Activity:通过调用setContentView() 方法,为Activity生成一个图形界面。因
此,Acrtivity是Android系统最重要的功能之一。


5.1 生命周期
在一个Android应用中可以有多个Activity,这些Activity组成了Activity栈
(Stack), 当前活动的Activity位于栈顶,之前的Activity被压入下面成为非活动
Activity,等待是否可能被恢复为活动状态。Activity的4个重要状态见表5-1。

表5-
1 
Activity的4个重要状态

序号状态说明
1 运行状态当前Activity,用户可见,可以获得焦点
2 暂停状态失去焦点的Activity,仍然可见
3 停止状态该Activity被其他Activity覆盖,不可见,会保存所有状态和信息
4 销毁状态该Activity结束

一个Activity从创建到消亡叫作一个生命周期,其中有很多有用的回调函数,方便截
获添加有价值的处理功能。Activity常用的回调函数见表5-2。

表5-
2 
Activity常用的回调函数

序号函数名称说明
1 onCreate() 创建Activity时被回调,执行更多的初始化功能,如添加消息响应

1 72 Android 简明程序设计
续表
序号函数名称说 明
2 onStart() 启动Activity时被回调,也就是当Activity变为可见时被回调
3 onResume() Activity由暂停态变为运行态时被调用
4 onPause() 暂停Activity时被调用,通常用于持久保存数据
5 onRestart() 重新启动Activity时被调用,在onStop()后运行
6 onStop() 停止Activity时被回调
7 onDestroy() 销毁Activity时被回调 
对Activity来说,onCreate()与onDestroy()函数都运行一次,其他回调函数可运行
多次,主要有4个流程,如下所示。
流程1:若焦点一直在Activity上,则流程为onCreate()->onStart()->onResume()-> 
正常运行界面的其他功能->onDestroy()正常销毁。
流程2:焦点有切换,假设有两个Activity,名称为a、b。初始时焦点在a上,则流程
为onCreate()->onStart()->onResume()->正常运行界面的其他功能;当切换到名称
为b的Activity时,对a来说,运行onPause->onStop();当焦点再切回到名称为a的
Activity时,对a来说,运行onRestart()->onStart()->onResume->正常运行界面的其
他功能。
流程3:从onPause()->onResume()函数,例如,当在某Activity中弹出某模态对话
框后,Activity运行onPause()函数,当关闭模态对话框后,Activity运行onResume() 
函数。流
程4:由App进程管理器直接销毁该Activity及对应的应用程序。
【例5-1】 验证Active各回调函数的执行顺序。
本示例仅能验证上文所述的流程1、流程2的情况。许多Android书都用日志监测
Activity各回调函数的执行流程,在集成开发环境中看日志较方便,但将该应用安装在真
实手机上看日志却并不方便。本示例利用图形用户界面显示Activity各回调函数响应的
各种情况,在集成开发平台与在真实手机中均非常方便。思路是:将Activity响应函数
名称显示在TextView控件中。各关键代码如下所示。
① 主布局文件:main.xml。 
<? xml version="1.0" encoding="utf-8"? > 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent"

第5 章 Activity 1 73 
android:layout_height="match_parent"> 
<TextView 
android:id="@+id/mytext" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:textSize="30sp"/> 
</LinearLayout> 
以上代码采用线性布局,定义了id为mytext的TextView 控件,用于显示Activity 
各回调函数的响应名称。
② MainActivity.java。 
public class MainActivity extends AppCompatActivity { 
void show(String name){ 
TextView tv = (TextView)findViewById(R.id.mytext); 
String s = tv.getText().toString(); 
tv.setText(s + "\n" +name); 
} 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.main); 
show("onCreate"); 
} 
protected void onStart() {super.onStart();show("onStart");} 
protected void onDestroy() {super.onDestroy();show("onDestroy");} 
protected void onStop() {super.onStop();show("onStop");} 
protected void onResume() {super.onResume();show("onResume");} 
protected void onPause() {super.onPause();show("onPause");} 
protected void onRestart() {super.onRestart();show("onRestart");} 
}
关键理解show(Stringname)函数,name即回调函数字符串名称。该函数首先获得
TextView组件上已有的内容,将其与当前name字符串相加,再重新设置回TextView。
5.2 建立Activity 
5.2.1 入口Activity类 
一个应用可以包含多个Activity活动页面,其入口Activity类对应应用的第一个界

1 74 Android 简明程序设计
面,之前经常用的MainActivity.java就是入口Activity类,如何区分入口Activity类与其
他普通Activity类? 这涉及应用配置文件Androidmanifest.xml(在res目录下),打开该
文件,可以看到与Activity类MainActivity对应的配置信息在<activity>标签内,如下
所示。 
<activity android:name=".MainActivity"> 
<intent-filter> 
<action android:name="android.intent.action.MAIN" /> 
<category android:name="android.intent.category.LAUNCHER" /> 
</intent-filter> 
</activity> 
<activity> 属性name= “.MainActivity”,标识了该Active 类的名称为
MainActivity,在工程默认包下。
<activity>子标签<intent-filter>定义了过滤器信息,对初学者而言,只要知道
<intent-filter>子标签<action>属性name=“android.intent.action.MAIN”,<category>属
性name=“android.intent.category.LAUNCHER”,那么它对应的Activity类就位于优先
级最高级,最先执行。
5.2.2 普通Activity类
从入口Active类类推,普通Activity类也应有如下内容:ActivityJava类、界面
XML布局文件、Androidmanifest.xml配置文件中增加的<activity>子标签内容。
【例5-2】 最简单的Activity启动程序。一般来说,已有工程已经包含入口Activity 
类MainActivity,现在要求再建立一个普通Activity类SecondActivity。MainActivity对
应的主界面(main.xml)有一按钮OK,当单击OK 按钮时,启动SecondActivity对应的界
面(main2.xml);SecondActivity对应的界面显示“Thisissecondactivity”,详细内容如下
所示。①
Activity类界面布局文件。 
//main.xml 
<? xml version="1.0" encoding="utf-8"? > 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent"> 
<Button 
android:id="@+id/myok"

第5 章 Activity 1 75 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:text="ok"/> 
</LinearLayout> 
//main2.xml 
<? xml version="1.0" encoding="utf-8"? > 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent"> 
<TextView 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:text="This is second activity"/> 
</LinearLayout> 
② 配置文件Androidmanifest.xml,以下仅列出与Activity有关的<activity>节点
内容。 
<activity android:name=".MainActivity"> 
<intent-filter> 
<action android:name="android.intent.action.MAIN" /> 
<category android:name="android.intent.category.LAUNCHER" /> 
</intent-filter> 
</activity> 
<activity android:name=".SecondActivity"></activity> 
可以看出,每增加一个普通Activity类,在配置文件中就增加一个<activity>节点, 
而且内容较简单,设定其name属性等于Activity类名称即可。
③ 对应的两个Activity类。 
//SecondActivity.java 
public class SecondActivity extends AppCompatActivity { 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.second); 
} 
} //MainActivity.java 
public class MainActivity extends AppCompatActivity { 
protected void onCreate(Bundle savedInstanceState) {

1 76 Android 简明程序设计 
super.onCreate(savedInstanceState); 
setContentView(R.layout.main); 
Button b = (Button)findViewById(R.id.myok); 
b.setOnClickListener(new View.OnClickListener() { 
public void onClick(View v) { 
Intent in = new Intent(MainActivity.this,SecondActivity.class); 
startActivity(in); 
} 
}); 
} 
}
可以看出,启动另一个Activity的关键函数是startActivity(Intentintent),因此必须
先产生Intent对象。Intent一个常用的构造方法是Intent(Contextctx,Class<?>cls),ctx 
是上下文对象,cls可以是待启动的Activity类的类名。
5.3 Activity 通信
Activity类间数据通信要应用Intent对象,Intent保存数据的本质是map映射(键- 
值),键一般是字符串,值可以是多种类型,Intent可读、可写,常用的函数如下所示。
. voidputExtra(Stringkey,XXXvalue),写单值函数,XXX 可以是8个基本数据
类型:byte、short、int、long、float、double、char、boolean。
. voidputExtra(Stringkey,XXXvalue[]),写数组函数,XXX 可以是8个基本数
据类型:byte、short、int、long、float、double、char、boolean。
. voidputExtra(Stringkey,CharSequence value),写字符串函数。
. voidputExtra(Stringkey,CharSequence value[]),写字符串数组函数。
. voidputExtra(Stringkey,Serializablevalue),写实现序列化对象函数。
. voidputExtras(Bundleb),写捆绑对象。
. xxxgetXxxExtra(Stringkey,xxxdefault),读基本数据类型,3个小写的“xxx” 
表示8种基本数据类型之一;首字符大写其余小写的“Xxx”,表示8种基本数据类
型名称首字符大写,其余小写。该函数的含义是:若读成功,则返回读的值,若读
不成功,则返回default值。
. xxx[]getXxxArrayExtra(Stringkey),读基本数据类型数组,若不成功,则返回null。
. StringgetStringExtra(Stringkey),读字符串数据。
. String[]getStringArrayExtra(Stringkey),读字符串数组数据。

第5 章 Activity 1 77 
. SerializablegetSerializableExtra(Stringkey),读序列化对象数据。
. BundlegetExtras(Stringkey),读捆绑对象。
假设有两个Activity类A、B,A 启动B,A、B间传参有以下情况:A 向B传送基本数
据类型;A 向B传送类对象类型;A 接收B销毁返回给A 的数据。下面以关键代码的形
式一一加以说明。
① A 向B传送基本数据类型,A 发送数据,B解析数据,见表5-3。
表5-3 基本数据类型发送解析关键代码
A发送数据B解析数据
方法1 
Intentout=newIntent(A.this,B.class); 
intno=1000;Stringname="zhang"; 
out.putExtra("no",no); 
out.putExtra("name",name); 
startActivity(out); 
Intentin=B.this.getIntent(); 
intno=in.getIntExtra("no",0); 
Stringname=in.getStringExtra("name"); 
方法2 
Bundleb=newBundle(); 
intno=1000;Stringname="zhang"; 
b.putInt("no",no); 
b.putString("name",name); 
Intentout= newIntent(A.this,B.class); 
out.putExtras(b); 
startActivity(out); 
Intentin=B.this.getIntent(); 
Bundleb=in.getExtras(); 
intno= b.getInt("no"); 
Stringname= b.getString("name"); 
② A 向B传送类对象类型,A 发送数据、B解析数据。
假设自定义Data类如下所示。 
class Data implements Serializable{ 
int no;String name; 
Data(int no,String name){this.no=no; this.name=name;} 
}
之所以实现Serializable接口,是因为要用到putExtra(Stringkey,Serializablevalue)函
数,value对应的类要求必须实现Serializable接口,其相应的发送、接收关键代码见表5-4。
表5-4 类对象数据发送、接收关键代码
A发送数据B解析数据
Datad=newData(1000,"zhang"); 
Intentout= newIntent(A.this,B.class); 
out.putExtra("data",d); 
startActivity(out); 
Intentin=this.getIntent(); 
Datad= (Data)in.getSerializableExtra("data"); 

178Android简明程序设计
利用Bundle捆绑数据也能实现类对象数据在Activity间的发送和解析,本题中的自
定义类也无须实现Serializable接口。请读者参照表5-3中的方法2实现相应的发送和接
收数据。

③A接收B销毁返回给A的数据。
为了更好地理解此部分知识,还需要掌握系统Activity类的3个基本函数,如下
所示。

.vitrtvtoRslItnnet,itrqetoe),与strciiy()函
odsatAciiyFreut(netitnneuscdatAtvt
数不同,本函数是具有接收返回结果的Activity启动函数,requestcode是请求识
别码。

.voidfinish(),结束当前Activity对象,返回到前一个Active对象。
t(e,Ia),e是结果识别码,a是准
备返回前一级Activity对象的数据。
另外,还要知道:若某Activity对象接收下一级Activity对象的返回数据,则必须重
写如下函数
oe
。
tdvitvteut(neetoe,itrslCdnetdt

.voidsetResulintresultcodntentdatresultcoddat
.prtceodonAciiyRslitrqusCdneutoe,Itnaa); 
很明显,dtrequstCdrsulCd
aa是返回的数据,eoe是请求码,etoe是结果码
。
实现A接收B销毁返回给A的数据的关键代码见表5-5
。


表5-
5 
实现
A 
接收B销毁返回给
A 
的数据的关键代码表

A中的关键代码

B中的关键代码

//A启动B代码

//B主动销毁时,直接调用以下函数
Itntout=newIntent(MainActivity.this,SecondActivity. BkPesed()//(o) 重(n) 写(a) o(r) (c) nBackPresed()函数clas);(e) (n) t(t,1);

ttAtiityFRlou

pblicvoidonBackPrsed(){//(s) A(a) 接收(c) B(v) 的返(o) 回值,(u) (s) (e) (r) (r) 必须重载下面函数

//(u) suproBcrsed();(e) 

e.nakPeprotectedvoidonAtivityReslintrequestCod

t(e, 

Intentout=newItnt();
intresultCode,I(c) tntdata){(u) 

ou.uEra(o,10(n) 00);(e) 

tptt"
"
uprociiyRslrqetoe,etoe,dta)
;


e.nAtvteut((e) (n) eusCdrlCda

setRult(2(x) ,out);(n) if(r(s) equestCode==1&&resultCde==2){(u) (s) 

finish();(s) (e) in}(o) =aagtnEta("o,0);(o) 

}

tndt.eItxrn" 

} 

B销毁有两种情况:一是响应B中的界面子组件事件,如按钮事件等;二是响应手机固
有的“返回”事件。这两种情况的响应函数本质上功能是一致的,因此本例重写了“返回” 
事件函数onBackPresed(),完成了向上一级Activity对象设置返回值及销毁本级


第
5 
章 Activity 
179 

Aciiy对象功能。在onakPed()函数内,注释了一行语句suproBcrsed(),若

tvtBcrsee.nakPe
把注释打开,运行程序后会发现A中的onActivityResult()函数不会接收B中传过来的
数据。这是因为B中的superonBackPresed()函数已经完成了销毁B的功能,在该行代
码下再设置向A发送的数据当然(.) 是无效了。

通过此例,再加深理解startActivityForResult(intent,requestCode)及setResult 
(e,t)中申请码re、结果码re的作用,这两个值最终都

resultCodintenequestCodesultCod
体现在onActivityResult(requestCode,resultCode,data)函数参数内:根据requestCode 
可知道是从哪个Activity对象返回的;根据resultCode,可以知道该如何解析data,因为
不同的resultCode可能代表不同的、有用的数据类型。


5.4 隐式启动Activity
前文所述启动Activity都是显示方式,主要体现在建立Intent对象时明确体现了启
动的ActvtItnn=nwItnticas), tvt

iiy对象。例如,netienet(A.hs,B.l则A是源Aciiy
类,B是待启动的Activity类。隐式启动Activity的含义是:在程序中看不出启动的
Actvty类,它是通过匹配查找配置文件Andodmaietxml中与Aciiy有关的内

iirinfs.tvt
容,找出应该启动哪个Activity类。

5.1 
itn-itr
4.netfle

在Androdmaietxml中,与Aciiy有关的主要是<aciiy>标签的子标签

inds.tvttvt

<intent-filter>的内容,对隐式启动的Activity来说,必须配置<intent-filter>的内容。

它主要包含<an> 、<cy>、<da>3个子标签的内容设置,下面一一加以

说明。
ctioategorat

①<action>标签。

action属性的值为一个字符串,它代表系统中已经定义了一系列常用的动作,形如
<actionandroid:name=“XXX”>,XXX可以自定义,也可以应用系统定义的常量,如下
所示。

.自定义动作字符串。
.ACTION_MAIN:AndroidApplication的入口,每个Android应用必须且只能包
含一个此类型的Action声明。
.ACTION_VIEW:系统根据不同的Data类型,通过已注册的对应Application显
示数据。

1 80 Android 简明程序设计
. ACTION_EDIT:系统根据不同的Data类型,通过已注册的对应Application编
辑数据。
. ACTION_DIAL:打开系统默认的拨号程序,如果Data中设置了电话号码,则自
动在拨号程序中输入此号码。
. ACTION_CALL:直接呼叫Data中所带的号码。
. ACTION_ANSWER:接听来电。
. ACTION_SEND:由用户指定发送方式进行数据发送操作。
. ACTION_SENDTO:系统根据不同的Data类型,通过已注册的对应Application 
进行数据发送操作。
所有系统定义的常量都要加前缀“android.intent.action.”,形如<actionandroid: 
name=“android.intent.action.ACTION_MAIN”>。
② <category>标签
<category>标签用于指定当前intent被处理的环境,一个intent-filter可以包含多
个category属性。
. 自定义种类字符串。
. CATEGORY_DEFAULT:Android系统中默认的执行方式,按照普通Activity 
的执行方式执行。
. CATEGORY_HOME:设置该组件为HomeActivity。
. CATEGORY_PREFERENCE:设置该组件为Preference。
. CATEGORY_LAUNCHER:设置该组件为在当前应用程序启动器中优先级最
高的Activity,通常与入口ACTION_MAIN 配合使用。
. CATEGORY_BROWSABLE:设置该组件可以使用浏览器启动。
. CATEGORY_GADGET:设置该组件可以内嵌到另外的Activity中。
所有系统定义的常量都要加前缀“android.intent.category.”,形如<category 
android:name=“android.intent.category.CATEGORY_DEFAULT”>。
③ <data>标签。
每个<data>标签都可以指定一个URI结构以及data的MIME类型。一个完整的
URI由scheme、host、port和path组成,其结构如下所示。 
<scheme>://<host>:<port>/<path> 
其中,scheme既可以是Android中常见的协议,也可以是自定义的协议。Android中常
见的协议包括content协议、http协议、file协议等,自定义协议可以使用自定义字符串。
<data>标签格式形如:<dataandroid:scheme="XXX"android:host="XXX">。