文章目录
- 目标
- 一、Activity的生命周期
- 目标
- 1.1 生命周期状态
- 1.2 生命周期方法
- 二、Activity的创建、配置、启动和关闭
- 目标
- 2.1 创建Activity
- 2.2 配置Activity
- 2.3 启动和关闭Activity
- 三、Intent与IntentFilter
- 目标
- 3.1 Intent
- 显式意图
- 隐式意图
- 3.2 IntentFilter
- (1)action属性匹配规则
- (2)data属性匹配规则
- (3)category属性匹配规则
- 四、Activity之间的跳转
- 目标
- 4.1 数据传递
- 使用Intent的putExtra()方法传递数据
- 使用Bundle类传递数据
- 4.2 Activity之间的数据回传
- 4.3 实战演练—小猴子摘桃
- 五、任务栈和启动模式
- 目标
- 5.1 Android中的任务栈
- 5.2 Activity的启动模式
- 六、使用Fragment
- 6.1 Fragment简介
- 6.2 Fragment生命周期
- 6.3 创建Fragment
- 6.4 在Activity中添加Fragment
- 6.5 实战演练—仿美团菜单
目标
- 熟悉Activity生命周期的方法,能够解释每个方法的作用
- 掌握Activity的创建、配置、开启和关闭的方式,能够完成创建、配置、开启和关闭Activity
- 熟悉
Intent
和IntentFilter
的内容,能够归纳Intent与IntentFilter的用法 - 熟悉Activity的任务栈和四种启动模式的内容,能够归纳任务栈和四种启动模式的作用
- 掌握Activity之间的跳转方式,能够独立实现Activity之间的跳转功能
- 掌握Fragment的使用,能够完成在Activity中添加Fragment
Android中的四大组件分别是Activity、Service、ContentProvider和BroadcastReceiver,其中,Activity是一个负责与用户交互的组件,每个Android应用中都会用Activity来显示界面以及处理界面上一些控件的事件。本章将针对Activity组件进行详细讲解,其他组件的介绍会在后续章节中讲解。
一、Activity的生命周期
目标
- 熟悉Activity生命周期的状态,能够归纳Activity生命周期的5种状态
- 熟悉Activity生命周期的方法,能够归纳Activity生命周期的7个方法
1.1 生命周期状态
每个人都是有生命的,在每个人出生到老去的过程中需要经历幼儿期、少年期、青春期、成年期和老年期5个阶段。
Activity与人一样也是有“生命”的,Activity从创建到销毁的整个过程就是Activity的生命周期,Activity的生命周期包含5种状态,这5种状态好比人类生命过程中经历的5个阶段。
1.2 生命周期方法
Activity的生命周期
包括创建、可见、获取焦点、失去焦点、不可见、重新可见、销毁等环节,针对每个环节Activity都定义了相关的回调方法
,Activity中的回调方法具体如下。
(1)onCreate():创建态,Activity创建时
调用,通常做一些初始化设置。
(2)onStart():启动态,Activity即将可见时
调用。
(3)onResume():运行态,Activity获取焦点时
调用。
(4)onPause():暂停态,当前Activity被其他Activity覆盖或屏幕锁屏时
调用。
(5)onStop():停止态,Activity对用户不可见时
调用。
(6)onRestart():重启态,Activity从停止状态到再次启动时
调用。
(7)onDestroy():销毁态,Activity销毁时
调用。
为了帮助开发者更好地理解Activity的生命周期,Google公司提供了Activity的生命周期模型
,如下图所示。
第一次运行程序
时:
调用的生命周期方法为:onCreate() -> onStart() -> onResume()。
退出程序
时:
调用的生命周期方法为:onPause() -> onStop() -> onDestory()。
横竖屏切换时Activity的生命周期
当手机横竖屏切换时,程序会根据AndroidManifest.xml文件中Activity的configChanges属性值的不同而调用相应的生命周期方法。
(1)没有设置configChanges属性
的值
当由竖屏切换为横屏时,调用的方法依次是onPause()、onStop()、onDestory()、onCreate()、onStart()和onResume()的方法。
(2)设置configChanges属性的值
<activity android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden" />
打开程序时同样会依次调用onCreate()、 onStart()、onResume()方法,但是当进行横竖屏切换时不会再执行其他的生命周期方法。
如果希望某一个界面一直处于竖屏或者横屏状态,并且此状态不随手机的晃动而改变,此效果可以通过在清单文件中设置Activity的screenOrientation属性
来实现。
竖屏:android:screenOrientation=“portrait”
横屏:android:screenOrientation=“landscape”
src\main\java\cn\itcast\activitylifecycle\MainActivity.java
package cn.itcast.activitylifecycle;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("MainActivity","调用onCreate()");
}
@Override
protected void onStart() {
super.onStart();
Log.i("MainActivity","调用onStart()");
}
@Override
protected void onResume() {
super.onResume();
Log.i("MainActivity","调用onResume()");
}
@Override
protected void onPause() {
super.onPause();
Log.i("MainActivity","调用onPause()");
}
@Override
protected void onStop() {
super.onStop();
Log.i("MainActivity","调用onStop()");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i("MainActivity","调用onDestroy()");
}
@Override
protected void onRestart() {
super.onRestart();
Log.i("MainActivity","调用onRestart()");
}
}
二、Activity的创建、配置、启动和关闭
目标
- 掌握Activity的创建、配置、启动和关闭方式,能够完成创建、配置、开启和关闭Activity
2.1 创建Activity
选中程序的包名右击选择【New】->【Activity】->【Empty Activity】选项,填写Activity信息,完成创建。
2.2 配置Activity
在Android程序中,创建Activity可以使用Java类继承Activity的方式实现。使用此种方式创建Activity时,需要在清单文件的标签中配置Acitivity。
<activity
android:name="cn.itcast.activitybasic.SecondActivity" />
如果不配置Activity
,则运行程序时,程序会抛出运行时异常。
在清单文件中引用Activity的方式
如果Activity所在的包与AndroidManifest.xml文件的标签中通过package属性指定的包名一致,则android:name属性的值可以直接设置为“.Activity名称”,以SecondActivity为例,示例代码如下:
<activity
android:name=".SecondActivity">
</activity>
2.3 启动和关闭Activity
- 启动Activity:startActivity()方法
以启动SecondActivity为例,示例代码如下
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);
- 关闭Activity:finish()方法
如果想要关闭当前的Activity,可以调用Activity提供的finish()方法。
三、Intent与IntentFilter
目标
- 掌握两种Intent类型的使用方式,能够灵活使用Intent的两种类型
- 掌握IntentFilter属性的匹配规则,能够独立配置IntentFilter的3个属性
3.1 Intent
Intent被称为意图,它不仅可以指定当前组件要执行的动作,还可以在不同组件之间进行数据传递。根据开启目标组件的方式不同,Intent被分为两种类型,分别为显式Intent和隐式Intent。
显式意图
显式Intent指的是直接指定目标组件,例如,使用Intent显式指定要跳转的目标Activity,示例代码如下:
//this当前Activity SecondActivity.class要启动的Activity
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent); //启动Activity
隐式意图
隐式Intent不会明确指出需要激活的目标组件,它被广泛地应用在不同应用程序之间传递消息。
Android系统会使用IntentFilter匹配属性action、data、category,这3个属性的具体介绍如下:
-
action:表示Intent对象要完成的动作。
-
data:表示Intent对象中传递的数据。
-
category:表示为action添加的额外信息。
在清单文件中,配置SecondActivity的action为“cn.itcast.START_ACTIVITY”的代码如下所示:
<activity android:name=".SecondActivity">
<intent-filter>
<!--设置action动作,当代码中的action与该action相匹配时启动该组件。-->
<action android:name="cn.itcast.START_ACTIVITY"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
在程序的MainActivity中开启SecondActivity的示例代码如下:
Intent intent = new Intent();
// 设置action动作,当与清单文件中的action相匹配时启动目标组件。
intent.setAction("cn.itcast.START_ACTIVITY");
startActivity(intent);
注意:在使用隐式Intent开启Activity时,系统会默认为该Intent添加category的属性name的值为“android.intent.category.DEFAULT”,所以将SecondActivity对应的标签中,属性android:name的值设置为“android.intent.category.DEFAULT”。
3.2 IntentFilter
当发送一个隐式Intent后,Android系统会将它与程序中的每一个组件的过滤器进行匹配,匹配属性有action、data和category,需要这3个属性都匹配成功才能唤起相应的组件。
(1)action属性匹配规则
action属性用来指定Intent对象的动作,具体示例代码如下:
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.VIEW" />
......
</intent-filter>
- 只要Intent携带的action与其中一个标签中action的声明相同,action属性就匹配成功。
注意:在清单文件中为Activity添加标签时,必须添加action属性,否则隐式Intent无法开启该Activity。
(2)data属性匹配规则
data属性用来指定数据的URI
或者数据MIME
类型,它的值通常与Intent的action属性有关联,具体示例代码如下:
<intent-filter>
<data android:mimeType="video/mpeg" android:scheme="http......" />
<data android:mimeType="audio/mpeg" android:scheme="http......" />
......
</intent-filter>
- 隐式Intent携带的data数据只要与IntentFilter中的任意一个data声明相同,data属性就匹配成功。
(3)category属性匹配规则
category属性用于为action添加额外信息,一个IntentFilter可以不声明category属性,也可以声明多个category属性,具体示例代码如下:
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
......
</intent-filter>
-
一个IntentFilter可以不声明category属性,也可以声明多个category属性。
-
隐式Intent中声明的category必须全部能够与某一个IntentFilter中的category匹配才算匹配成功。
注意:IntentFilter中罗列的category属性数量必须大于或者等于隐式Intent携带的category属性数量时,category属性才能匹配成功。如果一个隐式Intent没有设置category属性,那么他可以通过任何一个IntentFilter(过滤器)的category匹配。
四、Activity之间的跳转
目标
- 掌握Activity之间的数据传递方式,能够使用Intent类与Bundle类传递数据
- 掌握Activity之间的数据回传方式,能够完成Activity之间的数据回传
4.1 数据传递
Android提供的Intent可以在界面跳转时传递数据。使用Intent传递数据有两种方式。
-
使用Intent的putExtra()方法传递数据
-
使用Bundle类传递数据
使用Intent的putExtra()方法传递数据
Activity之间需要传递不同类型的数据,所以Android系统提供了多个重载的putExtra()方法。
使用Bundle类传递数据
4.2 Activity之间的数据回传
Activity之间进行数据回传时包含3个方法,分别是startActivityForResult()
方法、setResult()
方法和onActivityResult()
方法。
(1) startActivityForResult()方法
用于开启一个Activity,当开启的Activity销毁时,会从销毁的Activity中返回数据。
// intent 意图对象
// requestCode 表示请求码,用于标识请求的来源
startActivityForResult(Intent intent, int requestCode)
(2)setResult() 方法
用于携带数据进行回传,该方法的语法格式如下:
// resultCode 表示返回码,用于标识返回的数据来自哪一个Activity
setResult(int resultCode, Intent intent)
(3)onActivityResult()方法
用于接收回传的数据,该方法的语法格式如下:
// requestCode 请求码
// resultCode 回传码
// data 回传数据
onActivityResult(int requestCode, int resultCode, Intent data)
程序会根据传递的参数requestCode与resultCode来识别数据的来源。
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivityForResult(intent,1); // 开启SecondActivity
Intent intent = new Intent();
intent.putExtra("data","Hello MainActivity");
setResult(2,intent); // 在SecondActivity 中添加返回数据
finish();
@Override
// SecondActivity被销毁之后在MainActivity中回调onActivityResult()方法,接收回传的数据
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1&&resultCode == 2){
String acquiredData= data.getStringExtra("data");
Toast.makeText(MainActivity.this,acquiredData,Toast.LENGTH_SHORT).show();
}
}
4.3 实战演练—小猴子摘桃
本节我们将通过一个小猴子摘桃的案例来演示Activity之间是如何进行数据回传的,本案例的界面效果如下图所示。
res\layout\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"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#008577"
android:gravity="center"
android:text="首页"
android:textColor="@android:color/white"
android:textSize="20sp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg"
android:gravity="center_vertical">
<ImageView
android:id="@+id/iv_monkey"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/monkey" />
<Button
android:id="@+id/btn_peach"
android:layout_width="80dp"
android:layout_height="30dp"
android:layout_marginLeft="30dp"
android:layout_marginTop="20dp"
android:layout_toRightOf="@id/iv_monkey"
android:background="@drawable/btn_peach"
android:text="去桃园"
android:textColor="@android:color/black" />
<ImageView
android:id="@+id/iv_peach"
android:layout_width="45dp"
android:layout_height="35dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="80dp"
android:src="@drawable/peach_pic" />
<TextView
android:id="@+id/tv_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="85dp"
android:layout_toRightOf="@id/iv_peach"
android:text="摘到0个"
android:textColor="@android:color/black"
android:textSize="16sp" />
</RelativeLayout>
</LinearLayout>
pickpeach\MainActivity.java实现首页界面的显示效果
package cn.itcast.pickpeach;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private Button btn_peach;
private TextView tv_count;
private int totalCount = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
btn_peach = findViewById(R.id.btn_peach);
tv_count = findViewById(R.id.tv_count);
btn_peach.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, PeachActivity.class);
startActivityForResult(intent, 1);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
@Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1&&resultCode==1) {
int count = data.getIntExtra("count", 0); //获取回传的数据
totalCount = totalCount + count;
tv_count.setText("摘到" + totalCount + "个");
}
}
}
res\layout\activity_peach.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"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#008577"
android:gravity="center"
android:text="桃园"
android:textColor="@android:color/white"
android:textSize="20sp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/tree_bg">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginTop="70dp"
android:background="@drawable/tree">
<Button
android:id="@+id/btn_one"
android:layout_width="45dp"
android:layout_height="35dp"
android:layout_marginLeft="85dp"
android:layout_marginTop="25dp"
android:background="@drawable/peach_pic" />
<Button
android:id="@+id/btn_two"
android:layout_width="45dp"
android:layout_height="35dp"
android:layout_below="@id/btn_one"
android:layout_marginLeft="50dp"
android:layout_marginTop="5dp"
android:background="@drawable/peach_pic" />
<Button
android:id="@+id/btn_three"
android:layout_width="45dp"
android:layout_height="35dp"
android:layout_below="@id/btn_one"
android:layout_marginLeft="25dp"
android:layout_marginTop="5dp"
android:layout_toRightOf="@id/btn_two"
android:background="@drawable/peach_pic" />
<Button
android:id="@+id/btn_four"
android:layout_width="45dp"
android:layout_height="35dp"
android:layout_below="@id/btn_two"
android:layout_marginLeft="15dp"
android:layout_marginTop="5dp"
android:background="@drawable/peach_pic" />
<Button
android:id="@+id/btn_five"
android:layout_width="45dp"
android:layout_height="35dp"
android:layout_below="@id/btn_two"
android:layout_marginLeft="25dp"
android:layout_marginTop="5dp"
android:layout_toRightOf="@id/btn_four"
android:background="@drawable/peach_pic" />
<Button
android:id="@+id/btn_six"
android:layout_width="45dp"
android:layout_height="35dp"
android:layout_below="@id/btn_two"
android:layout_marginLeft="25dp"
android:layout_marginTop="5dp"
android:layout_toRightOf="@id/btn_five"
android:background="@drawable/peach_pic" />
</RelativeLayout>
<Button
android:id="@+id/btn_exit"
android:layout_width="80dp"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_margin="50dp"
android:background="@drawable/btn_peach"
android:text="退出桃园"
android:textColor="@android:color/black" />
</RelativeLayout>
</LinearLayout>
pickpeach\PeachActivity.java实现桃园界面的摘桃效果
package cn.itcast.pickpeach;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class PeachActivity extends AppCompatActivity implements
View.OnClickListener {
private Button btn_one, btn_two, btn_three, btn_four, btn_five,btn_six,btn_exit;
private int count=0;//桃子个数
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_peach);
init();
}
private void init() {
btn_one = findViewById(R.id.btn_one);
btn_two = findViewById(R.id.btn_two);
btn_three = findViewById(R.id.btn_three);
btn_four = findViewById(R.id.btn_four);
btn_five = findViewById(R.id.btn_five);
btn_six = findViewById(R.id.btn_six);
btn_exit = findViewById(R.id.btn_exit);
btn_one.setOnClickListener(this);
btn_two.setOnClickListener(this);
btn_three.setOnClickListener(this);
btn_four.setOnClickListener(this);
btn_five.setOnClickListener(this);
btn_six.setOnClickListener(this);
btn_exit.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn_one: //第一个桃子的点击事件
info(btn_one);
break;
case R.id.btn_two: //第二个桃子的点击事件
info(btn_two);
break;
case R.id.btn_three: //第三个桃子的点击事件
info(btn_three);
break;
case R.id.btn_four: //第四个桃子的点击事件
info(btn_four);
break;
case R.id.btn_five: //第五个桃子的点击事件
info(btn_five);
break;
case R.id.btn_six: //第六个桃子的点击事件
info(btn_six);
break;
case R.id.btn_exit: //“退出桃园”按钮的点击事件
returnData();
break;
}
}
/**
* 按钮的点击事件处理
*/
private void info(Button btn){
count++; //桃子个数加1
btn.setVisibility(View.INVISIBLE);
Toast.makeText(PeachActivity.this,"摘到"+count+"个桃子",
Toast.LENGTH_LONG).show();
}
/**
* 将数据回传到上个界面
*/
private void returnData(){
Intent intent = new Intent();
intent.putExtra("count",count);
setResult(1,intent);
PeachActivity.this.finish();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_BACK&&event.getRepeatCount()==0){
returnData(); //调用数据回传方法
}
return false;
}
}
五、任务栈和启动模式
目标
- 熟悉Android中的任务栈,能够归纳Activity在任务栈中的存放情况
- 熟悉Activity的启动模式,能够解释Activity的4种启动模式
5.1 Android中的任务栈
任务栈:一种用来存放Activity实例的容器。
特点:“先进后出”
操作:压栈和出栈
5.2 Activity的启动模式
Activity启动模式有四种,分别是standard、singleTop、singleTask和singleInstance模式。
(1) standard模式
standard模式是Activity的默认启动方式,每启动一个Activity就会在栈顶创建 一个新的实例。
(2)singleTop模式
singleTop模式a会判断要启动的Activity实例是否位于栈顶,如果位于栈顶则直接复用,否则创建新的实例。
(3)singleTask模式
singleTask模式下每次启动该Activity时,系统首先会<font color='limeGreen'>检查栈中是否存在当前Activity实例</font>,如果存在则直接使用,并<font color='limeGreen'>把当前Activity之上的所有实例全部出栈。</font>
(4)singleInstance模式
singleInstance模式会启动一个新的任务栈来管理Activity实例,无论从哪个任务栈中启动该Activity,该实例在整个系统中只有一个。
六、使用Fragment
- 熟悉Fragment的简介和生命周期,能够解释Fragment的定义和生命周期中的方法
- 掌握Fragment的创建方式,能够独立完成Fragment的创建
- 掌握在Activity中添加Fragment的方式,能够独立完成在Activity中添加Fragment
6.1 Fragment简介
Fragment(碎片)是一种嵌入在Activity中的UI片段,它可以用来描述Activity中的一部分布局。
6.2 Fragment生命周期
Fragment不能独立存在,必须嵌入到Activity中使用,所以Fragment生命周期直接受所在的Activity影响。
-
当在Activity中创建Fragment时,Fragment处于启动状态;
-
当Activity被暂停时,其中的所有Fragment也被暂停;
-
当Activity被销毁时,所有在该Activity中的Fragment也被销毁。
-
当一个Activity处于运行状态时,可以单独地对每一个Fragment进行操作,如添加或删除,当添加时,Fragment处于启动状态。当删除时,Fragment处于销毁状态。
6.3 创建Fragment
与Activity类似,创建Fragment时必须创建一个类继承Fragment。
public class NewsListFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 第1个参数表示Fragment对应的布局资源ID
// 第2个参数表示存放Fragment视图的父视图
// 第3个参数表示是否将生成的视图添加到父视图
View v = inflater.inflate(R.layout.fragment, container, false);
return v;
}
}
注意
Android系统中提供了2个Fragment类,这两个类分别是android.app.Fragment和android.support.v4.app.Fragment。
(1)如果NewsListFragment类继承的是android.app.Fragment
类,则程序只能兼容3.0版本以上的Android系统。
(2)如果NewsListFragment类继承的是android.support.v4.app.Fragment
类,则程序可以兼容1.6版本以上的Android系统。
6.4 在Activity中添加Fragment
Fragment创建完成后并不能单独使用,还需要将Fragment添加到Activity中。在Activity中添加Fragment有两种方式。
- 在布局文件中添加Fragment
- 在Activity中动态加载Fragment
在布局文件中添加Fragment
<fragment
android:name="cn.itcast.NewsListFragment" <!--Fragment的全路径名称-->
android:id="@+id/newslist"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
在Activity中动态加载Fragment
当Activity运行时,也可以将Fragment动态添加到Activity中,具体步骤如下:
(1) 创建一个Fragment的实例对象。
(2) 获取FragmentManager类的实例。
(3) 开启FragmentTransaction(事务)。
(4) 向Activity的布局容器(一般为FrameLayout)中添加Fragment。
(5) 通过commit()方法提交事务。
NewsListFragment fragment = new NewsListFragment
FragmentManager fm = getFragmentManager();
FragmentTransaction beginTransaction = fm.beginTransaction(); // 开启事务
beginTransaction.replace(R.id.ll,fragment); // 添加一个Fragment
beginTransaction.commit(); // 提交事务
6.5 实战演练—仿美团菜单
本节我们以仿美团外卖菜单的案例为例来演示如何在一个Activity中展示两个Fragment,并实现Activity与Fragment之间的通信功能。本案例的界面效果如下图所示。
res\layout\left_layout.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"
android:background="#f7f8f9"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/tv_recommend"
style="@style/tvLeftStyle"
android:text="推荐"
android:background="@android:color/white"/>
<TextView
android:id="@+id/tv_must_buy"
style="@style/tvLeftStyle"
android:text="进店必买" />
</LinearLayout>
res\layout\right_layout.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"
android:background="@android:color/white"
android:orientation="vertical">
<ListView
android:id="@+id/lv_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@null"/>
</LinearLayout>
res\layout\list_item.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"
android:orientation="horizontal"
android:padding="4dp">
<ImageView
android:id="@+id/iv_img"
android:layout_width="70dp"
android:layout_height="70dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="2dp"
android:textColor="@android:color/black"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_sale"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#868788"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:textColor="#e85b4d"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
res\layout\activity_main.xml搭建菜单界面布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginBottom="4dp"
android:background="@color/gray"
android:gravity="center_vertical">
<TextView
android:id="@+id/tv_order"
style="@style/tvNavigationBarStyle"
android:text="点菜"
android:textColor="@android:color/black" />
<TextView
android:id="@+id/tv_discuss"
style="@style/tvNavigationBarStyle"
android:layout_toRightOf="@id/tv_order"
android:text="评价"
android:textColor="@color/dark_gray" />
<TextView
android:id="@+id/tv_business"
style="@style/tvNavigationBarStyle"
android:layout_toRightOf="@id/tv_discuss"
android:text="商家"
android:textColor="@color/dark_gray" />
<TextView
android:layout_width="70dp"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:background="@drawable/friend_list"
android:gravity="center"
android:text="好友拼单"
android:textColor="#ef842c"
android:textSize="12sp" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<fragment
android:id="@+id/left"
android:name="cn.itcast.menu.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
tools:layout="@layout/left_layout" />
<fragment
android:id="@+id/right"
android:name="cn.itcast.menu.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
tools:layout="@layout/right_layout" />
</LinearLayout>
</LinearLayout>
menu\FoodBean.java封装菜品信息的实体类
package cn.itcast.menu;
import java.io.Serializable;
public class FoodBean implements Serializable {
//序列化时保持FoodBean类版本的兼容性
private static final long serialVersionUID = 1L;
private String name; //菜品名称
private String sales; //月售信息
private String price; //菜品价格
private int img; //菜品图片
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSales() {
return sales;
}
public void setSales(String sales) {
this.sales = sales;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public int getImg() {
return img;
}
public void setImg(int img) {
this.img = img;
}
}
menu\LeftFragment.java加载左侧菜单栏界面布局
package cn.itcast.menu;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class LeftFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view =inflater.inflate(R.layout.left_layout,container,false);
return view;
}
@Override
public void onPause() {
super.onPause();
}
}
menu\RightAdapter.java编写菜单列表的适配器
package cn.itcast.menu;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class RightAdapter extends BaseAdapter {
private Context mContext;
private List<FoodBean> list;
public RightAdapter(Context context ,List<FoodBean> list) {
this.mContext = context;
this.list=list;
}
@Override
public int getCount() { //获取列表条目的总数
return list.size(); //返回ListView 条目的总数
}
@Override
public Object getItem(int position) {
return list.get(position); //返回列表条目的数据对象
}
@Override
public long getItemId(int position) {
return position; //返回列表条目的id
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = View.inflate(mContext, R.layout.list_item, null);
holder = new ViewHolder();
holder.tv_name = convertView.findViewById(R.id.tv_name);
holder.tv_sale = convertView.findViewById(R.id.tv_sale);
holder.tv_price = convertView.findViewById(R.id.tv_price);
holder.iv_img = convertView.findViewById(R.id.iv_img);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
FoodBean bean=list.get(position);
holder.tv_name.setText(bean.getName());
holder.tv_sale.setText(bean.getSales());
holder.tv_price.setText(bean.getPrice());
holder.iv_img.setBackgroundResource(bean.getImg());
return convertView;
}
class ViewHolder {
TextView tv_name, tv_sale,tv_price;
ImageView iv_img;
}
}
menu\RightFragment.java加载右侧菜单栏界面布局
package cn.itcast.menu;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import java.io.Serializable;
import java.util.List;
public class RightFragment extends Fragment {
private ListView lv_list;
public RightFragment() {
}
public RightFragment getInstance(List<FoodBean> list) {
RightFragment rightFragment = new RightFragment();
//通过Bundle对象传递数据可以保证在设备横竖屏切换时传递的数据不丢失
Bundle bundle = new Bundle();
//将需要传递的字符串以键值对的形式传入bundle对象
bundle.putSerializable("list", (Serializable) list);
rightFragment.setArguments(bundle);
return rightFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.right_layout, container, false);
lv_list = view.findViewById(R.id.lv_list);
if (getArguments() != null) {
List<FoodBean> list = (List<FoodBean>) getArguments().
getSerializable("list");
RightAdapter adapter = new RightAdapter(getActivity(), list);
lv_list.setAdapter(adapter);
}
return view;
}
}
menu\MainActivity.java实现显示菜单的效果
package cn.itcast.menu;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
private FragmentManager fragmentManager;
private FragmentTransaction fragmentTransaction;
private LeftFragment leftFragment;
private TextView tv_recommend, tv_must_buy;
private RightFragment rightFragment;
//推荐菜单列表数据
private String[] names1 = {"爆款*肥牛鱼豆腐骨肉相连三荤五素一份米饭", "豪华双人套餐",
"【热销】双人套餐(含两份米饭)"};
private String[] sales1 = {"月售520 好评度80%", "月售184 好评度68%",
"月售114 好评度60%"};
private String[] prices1 = {"¥23", "¥41", "¥32"};
private int[] imgs1 = {R.drawable.recom_one, R.drawable.recom_two,
R.drawable.recom_three};
//进店必买菜单列表数据
private String[] names2 = {"'蔬菜主义'1人套餐", "2人经典套餐", "3人经典套餐"};
private String[] sales2 = {"月售26 好评度70%", "月售12 好评度50%",
"月售4 好评度40%"};
private String[] prices2 = {"¥44", "¥132", "¥180"};
private int[] imgs2 = {R.drawable.must_buy_one, R.drawable.must_buy_two,
R.drawable.must_buy_three};
private Map<String,List<FoodBean>> map;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setData();
init();
clickEvent();
}
private void init() {
fragmentManager = getFragmentManager();//获取fragmentManager
//通过findFragmentById()方法获取leftFragment
leftFragment = (LeftFragment) fragmentManager.findFragmentById(R.id.left);
//获取左侧菜单栏中的控件
tv_recommend = leftFragment.getView().findViewById(R.id.tv_recommend);
tv_must_buy = leftFragment.getView().findViewById(R.id.tv_must_buy);
}
private void setData(){
map=new HashMap<>();
List<FoodBean> list1=new ArrayList<>();
List<FoodBean> list2=new ArrayList<>();
for (int i=0;i<names1.length;i++){
FoodBean bean=new FoodBean();
bean.setName(names1[i]);
bean.setSales(sales1[i]);
bean.setPrice(prices1[i]);
bean.setImg(imgs1[i]);
list1.add(bean);
}
map.put("1",list1);//将推荐菜单列表的数据添加到map集合中
for (int i=0;i<names2.length;i++){
FoodBean bean=new FoodBean();
bean.setName(names2[i]);
bean.setSales(sales2[i]);
bean.setPrice(prices2[i]);
bean.setImg(imgs2[i]);
list2.add(bean);
}
map.put("2",list2); //将进店必买菜单列表的数据添加到map集合中
}
private void clickEvent() {
tv_recommend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//调用switchData()方法填充Rightfragment中的数据
switchData(map.get("1"));
tv_recommend.setBackgroundColor(Color.WHITE);
tv_must_buy.setBackgroundResource(R.color.gray);
}
});
tv_must_buy.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switchData(map.get("2"));
tv_must_buy.setBackgroundColor(Color.WHITE);
tv_recommend.setBackgroundResource(R.color.gray);
}
});
//设置首次进入界面后,默认需要显示的数据
switchData(map.get("1"));
}
/**
* 填充Activity右侧的Fragment,并传递列表数据list
*/
public void switchData(List<FoodBean> list) {
fragmentManager = getFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();//开启一个事务
//通过调用getInstance()方法实例化RightFragment
rightFragment = new RightFragment().getInstance(list);
//调用replace()方法
fragmentTransaction.replace(R.id.right, rightFragment);
fragmentTransaction.commit();
}
}