深入理解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);