深入理解Activity与Fragment

第5章

本章学习目标

.掌握Activity的创建与使用。
.熟悉Activity的生命周期。
.掌握Fragment的创建与使用。
.熟悉Fragment的生命周期。
Android应用中,Activity、Service、BroadcastReceiver和ContentProvider这四大基本
组件是Android开发必学内容,而Activity是其中最重要的一项。它负责与用户交互,并向
用户呈现应用的状态,通常一个Android应用由
N 
个Activity组成。Fragment代表了
Activity的子模块,与Activity一样,Fragment也有自己的生命周期。通过本章节的学习, 
熟悉Activity与Fragment的生命周期,以及掌握它们的建立与使用方法。

5.创建、ciiy
1 
配置和使用Atvt

5.1 
Atvty介绍
1.cii

学习一个新知识点时,总要追根溯源才能彻底掌握。学习Activity也不例外,Activity
直接或间接继承了Cotxt、CnetWrppr、Cotxae1 

所示。
neotxaenetThemeWrppr等基类,如图5.

在使用Activity时,需要用户继承Activity基类。在不同的应用场景下,可以选择继承
Activity的子类。例如界面中只包括列表,则可以继承ListActivity;若界面需要实现标签
页效果,则要继承TabActivity。

当一个Activity类被定义出来之后,这个Activity类何时被实例化、它所包含的方法何
时被调用都是由Andd系统决定的。用户只负责实现相应的方法创建出需要的Ac
即可。
roitivity 

创建一个Activity需要实现一个或多个方法,其中最基本的方法是onCreate(Bundle 
status),它将会在Activity被创建时回调,然后通过setContentView(Viewview)方法显示
要展示的布局文件。这个知识点在第1章介绍HeloWorld项目时就提到过。

接下来看一个LauncherActivity的例子。从图5.auncherActivity继承自

1可以看到LListActivity,所以它本质也是一个开发列表界面的Activity,但不同的是,它的每个列表项
都对应一个Intent,因此当用户点击不同的列表项时,应用程序会自动启动对应的Activity。



Android 移动开发与项目实战(微课视频版) 
1 24 
图5.1 Activity类
具体如例5.1所示。
例5.1 LauncherActivity用法示例 
1 package com.example.chapater5_1; 
2 import android.app.LauncherActivity; 
3 import android.content.Intent; 
4 import android.os.Bundle; 
5 import android.widget.ArrayAdapter; 
6 public class MainActivity extends LauncherActivity { 
7 //定义两个Activity 的名称
8 String[] names = {"FirstActivity", "SecondActivity"}; 
9 //定义两个Activity 
10 Class<? >[] clazzs = {FirstActivity.class, SecondActivity.class}; 
11 @Override 
12 protected void onCreate(Bundle savedInstanceState) { 
13 super.onCreate(savedInstanceState); 
14 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, 
15 android.R.layout.simple_list_item_1, names); 
16 //设置列表所需的Adapter 
17 setListAdapter(adapter); 
18 }

1 25 
第5章
深入理解Activity 与Fragment 
19 //根据列表项返回指定Activity 对应的Intent 
20 @Override 
21 protected Intent intentForPosition(int position) { 
22 return new Intent(MainActivity.this, clazzs[position]); 
23 } 
24 } 
需要注意的是,上面代码中onCreate(BundlesavedInstanceState)方法中没有使用
setContentView(Viewview)加载view,而是使用ArrayAdapter加载了一个列表。这也是
ListActivity的不同之处。intentForPosition(intposition)方法根据用户点击的列表项启动
相应的Activity。布局文件simple_layout_item.xml是一个根标签为TextView 的布局,用
于加载names列表。
至此LauncherActivity的示例已经完成,但是这只是创建完成了MainActivity,只有在
AndroidManifest.xml文件中配置了MainActivity才可以使用。读者可能已经发现,之前
的很多例子中也是在MainActivity中操作完成的,同样可以在模拟器上运行,这里为什么
就不行呢? 这是因为Android Studio 自动在AndroidMainfest.xml 文件中配置了
MainActivity,所以才能直接使用。
5.1.2 配置Activity 
5.1.1节提到Activity必须在AndroidManifest.xml清单文件中配置才可以使用,而在
AndroidStudio中是自动配置完成,但是有时自动配置完成的属性并不能满足需求。来看
配置Activity时常用的属性,如表5.1所示。
表5.1 配置Activity属性
属 性说 明
name 指定Activity的类名
icon 指定Activity对应的图标
label 指定Activity的标签
exported 指定该Activity是否允许被其他应用调用
launchMode 指定Activity的启动模式 
除了上述几个属性之外,Activity中还可以设置一个或多个<intent-filter…/>元素, 
该元素用于指定该Activity相应的Intent。
下面来看例5.1中清单文件配置的3个Activity。 
<activity android:name=".SecondActivity"></activity> 
<activity android:name=".FirstActivity" /> 
<activity android:name=".MainActivity"> 
<intent-filter> 
<action android:name="android.intent.action.MAIN" />

Android 移动开发与项目实战(微课视频版) 
1 26 
<category android:name="android.intent.category.LAUNCHER" /> 
</intent-filter> 
</activity> 
上述配置代码配置了3个Activity,其中第一个Activity配置了<intent-filter…/>元
素,指定了该Activity作为程序的入口。运行例5.1程序,将会看到如图5.2所示的界面。
点击第1个列表项FirstActivity,会出现如图5.3所示的界面。
图5.2 LauncherActivity运行结果 
图5.3 点击LauncherActivity第一个列表项后
点击第2个列表项出现的结果与第一个一样,故这里不做展示。
5.1.3 Activity的启动与关闭
在一个Android应用程序中通常会有多个Activity,每个Activity都是可以被其他
Activity启动的,但程序只有一个Activity作为入口,即程序启动时只会启动作为入口的
Activity,其他Activity会被已经启动的其他Activity启动。
启动Activity的方式有以下两种。
.startActivity(Intentintent):启动其他Activity。
. startActivityForResult(Intentintent,intrequestCode): 以指定的请求码
(requestCode)启动新Activity,并且原来的Activity会获取新启动的Activity返回
的结果(需重写onActivityResult()方法)。
启动Activity有两种方式,关闭Activity也有两种方式。
.finish():关闭当前Activity。
.finishActivity(intrequestCode):结束以startActivityForResult(Intentintent,int 
requestCode)方法启动的Activity。

1 27 
第5章
深入理解Activity 与Fragment 
接下来示范Activity的启动,以及实现两个Activity的切换。具体如例5.2所示。
例5.2 Activity的显式与隐式启动,两个Activity之间的切换 
1 package com.example.chapater5_2; 
23
import android.content.Intent; 
4 import android.os.Bundle; 
5 import android.view.View; 
6 import android.widget.Button; 
78
import androidx.appcompat.app.AppCompatActivity; 
9 10 public class MainActivity extends AppCompatActivity { 
11 
12 @Override 
13 protected void onCreate(Bundle savedInstanceState) { 
14 super.onCreate(savedInstanceState); 
15 setContentView(R.layout.activity_main); 
16 Button button1 = findViewById(R.id.btn1); 
17 Button button2 = findViewById(R.id.btn2); 
18 Button button3 = findViewById(R.id.btn3); 
19 
20 //显式启动Activity 
21 button1.setOnClickListener(new View.OnClickListener() { 
22 @Override 
23 public void onClick(View v) { 
24 Intent intent = new Intent(MainActivity.this, 
25 SecondActivity.class); 
26 startActivity(intent); 
27 } 
28 }); 
29 
30 //调用setClassName()方法显式启动Activity 
31 button2.setOnClickListener(new View.OnClickListener() { 
32 @Override 
33 public void onClick(View v) { 
34 Intent intent = new Intent(); 
35 //第一个参数是包名,第二个参数是类的全路径名
36 intent.setClassName("com.example.chapater5_2", 
37 "com.example.chapater5_2.SecondActivity"); 
38 startActivity(intent); 
39 } 
40 }); 
41

Android 移动开发与项目实战(微课视频版) 
1 28 
42 //隐式启动
43 button3.setOnClickListener(new View.OnClickListener() { 
44 @Override 
45 public void onClick(View v) { 
46 Intent intent = new Intent(); 
47 intent.setAction("com.example.chapater5_2.SecondActivity"); 
48 startActivity(intent); 
49 } 
50 }); 
51 } 
52 } 
53 
上述代码对应的布局文件中只有3个按钮,不做展示。这里示范了两种启动Activity 
的形式,要注意的是显式启动时用setClassName(StringpackageName,StringclassName) 
方法,第1个参数是包名,第2个参数是类的全路径名。隐式启动的方式之前没有例子涉
及,它需要在清单文件中对应的Activity中设置action标签,并且与代码中的setAction() 
中设置的内容一样。下面来看清单文件中SecondAtivity中的配置。 
1 <activity android:name=".SecondActivity" > 
2 <intent-filter> 
3 <action android:name="com.example.helloworld.SecondActivity"/> 
4 <category android:name="android.intent.category.DEFAULT" /> 
5 </intent-filter> 
6 </activity> 
清单文件中的代码与隐式启动的setAction()方法中一定要一样。其实隐式启动时
Android系统会根据清单文件中设置的action、category、uri找到最合适的组件,只不过本
例中设置category 为“android.intent.category.DEFAULT”是一种默认的类别,在调用
startActivity()时会自动将这个category添加到Intent。
接下来看SecondActivity中的代码。 
1 package com.example.chapater5_2; 
23
import android.content.Intent; 
4 import android.os.Bundle; 
5 import android.view.View; 
6 import android.widget.Button; 
7 import androidx.appcompat.app.AppCompatActivity; 
89
public class SecondActivity extends AppCompatActivity { 
10 
11 @Override

1 29 
第5章
深入理解Activity 与Fragment 
12 protected void onCreate(Bundle savedInstanceState) { 
13 super.onCreate(savedInstanceState); 
14 setContentView(R.layout.second_layout); 
15 Button button1 = findViewById(R.id.btn1); 
16 Button button2 = findViewById(R.id.btn2); 
17 button1.setOnClickListener(new View.OnClickListener() { 
18 @Override 
19 public void onClick(View v) { 
20 Intent intent = new Intent(SecondActivity.this, 
21 MainActivity.class); 
22 startActivity(intent); 
23 } 
24 }); 
25 
26 button2.setOnClickListener(new View.OnClickListener() { 
27 @Override 
28 public void onClick(View v) { 
29 Intent intent = new Intent(SecondActivity.this, 
30 MainActivity.class); 
31 startActivity(intent); 
32 finish(); 
33 } 
34 }); 
35 } 
36 } 
上述代码中有两个监听器,只是一个有finish()方法而另一个没有。如果有finish()则
表示点击按钮后会关闭自己。
5.1.4 使用Bundle在Activity之间交换数据
在实际开发中,一个Activity 启动另一个Activity 时经常需要传输数据过去。在
Activity之间交换数据很简单,使用Intent即可。在启动新的Activity时,利用Intent提供
的多种方法将数据传递过去。常用的方法如表5.2所示。
表5.2 传递数据时常用的方法
方 法作 用
putExtras(Bundledata) 向Intent中放入需要携带的数据包
getExtras() 取出Intent所携带的数据包
putExtra(Stringname,Xxxvalue) 向Intent中放入key-value形式的数据
getXxxExtra(Stringname) 按key取出Intent中指定类型的数据
putXxx(Stringkey,Xxxdata) 向Bundle中放入各种类型的数据

续表
Android 移动开发与项目实战(微课视频版) 
1 30 
方 法作 用
getXxx(Stringkey) 从Bundle中取出各种类型的数据
putSerializable(Stringkey,Serializabledata) 向Bundle中放入一个可序列化的对象
getSerializable(Stringkey,Serializabledata) 从Bundle中取出一个可序列化的对象 
Intent主要通过Bundle对象来携带数据,使用到的方法都如表5.2所示。下面通过一
个示例示范两个Activity通过Bundle交换数据,假设千锋需要学生的基本信息,学生在填
写资料之后提交到下一个页面,具体代码如例5.3所示。
例5.3 信息填写页面的布局文件 
1 <? xml version="1.0" encoding="utf-8"? > 
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
3 android:orientation="vertical" android:layout_width="match_parent" 
4 android:layout_height="match_parent"> 
56 
<LinearLayout 
7 android:layout_width="match_parent" 
8 android:layout_height="wrap_content" 
9 android:orientation="horizontal"> 
10 <TextView 
11 android:layout_width="wrap_content" 
12 android:layout_height="wrap_content" 
13 android:text="昵称:"/> 
14 <EditText 
15 android:id="@+id/nickName" 
16 android:layout_width="match_parent" 
17 android:layout_height="wrap_content"/> 
18 </LinearLayout> 
19 <LinearLayout 
20 android:layout_width="match_parent" 
21 android:layout_height="wrap_content" 
22 android:orientation="horizontal"> 
23 <TextView 
24 android:layout_width="wrap_content" 
25 android:layout_height="wrap_content" 
26 android:text="年龄:"/> 
27 <EditText 
28 android:id="@+id/age" 
29 android:layout_width="match_parent" 
30 android:layout_height="wrap_content" /> 
31 </LinearLayout> 
32

1 31 
第5章
深入理解Activity 与Fragment 
33 <LinearLayout 
34 android:layout_width="match_parent" 
35 android:layout_height="wrap_content" 
36 android:orientation="horizontal"> 
37 <TextView 
38 android:layout_width="wrap_content" 
39 android:layout_height="wrap_content" 
40 android:text="性别:"/> 
41 <RadioGroup 
42 android:layout_width="match_parent" 
43 android:layout_height="wrap_content"> 
44 <RadioButton 
45 android:id="@+id/male" 
46 android:layout_width="wrap_content" 
47 android:layout_height="wrap_content" 
48 android:text="男"/> 
49 <RadioButton 
50 android:id="@+id/female" 
51 android:layout_width="wrap_content" 
52 android:layout_height="wrap_content" 
53 android:text="女"/> 
54 </RadioGroup> 
55 </LinearLayout> 
56 <LinearLayout 
57 android:layout_width="match_parent" 
58 android:layout_height="wrap_content" 
59 android:orientation="horizontal"> 
60 <TextView 
61 android:layout_width="wrap_content" 
62 android:layout_height="wrap_content" 
63 android:text="学历:"/> 
64 <EditText 
65 android:id="@+id/qualifications" 
66 android:layout_width="match_parent" 
67 android:layout_height="wrap_content"/> 
68 </LinearLayout> 
69 <LinearLayout 
70 android:layout_width="match_parent" 
71 android:layout_height="wrap_content" 
72 android:orientation="horizontal"> 
73 <TextView 
74 android:layout_width="wrap_content" 
75 android:layout_height="wrap_content" 
76 android:text="电话:"/>

Android 移动开发与项目实战(微课视频版) 
1 32 
77 <EditText 
78 android:id="@+id/phone" 
79 android:layout_width="match_parent" 
80 android:layout_height="wrap_content"/> 
81 </LinearLayout> 
82 <!--确认--> 
83 <Button 
84 android:id="@+id/submit" 
85 android:layout_width="match_parent" 
86 android:layout_height="wrap_content" 
87 android:text="提交"/> 
88 </LinearLayout> 
上述布局文件采用LinearLayout方式,对应的Java代码如下所示。 
1 package com.example.chapater5_3; 
23
import android.content.Intent; 
4 import android.os.Bundle; 
5 import android.view.View; 
6 import android.widget.Button; 
7 import android.widget.EditText; 
8 import android.widget.RadioButton; 
9 10 import androidx.appcompat.app.AppCompatActivity; 
11 
12 public class MainActivity extends AppCompatActivity { 
13 
14 private EditText nickName, age, qualifications, phone; 
15 private RadioButton male, female; 
16 private Button submit; 
17 
18 @Override 
19 protected void onCreate(Bundle savedInstanceState) { 
20 super.onCreate(savedInstanceState); 
21 setContentView(R.layout.activity_main); 
22 
23 setTitle("学生信息调查"); 
24 submit = findViewById(R.id.submit); 
25 submit.setOnClickListener(new View.OnClickListener() { 
26 @Override 
27 public void onClick(View v) { 
28 nickName = findViewById(R.id.nickName); 
29 age = findViewById(R.id.age);