Fragment(11)——回退栈管理
前言
在Fragment的使用过程中,我们经常会遇到Fragment的启动和关闭的问题,我们当然可以使用add及remove系列方法来实现Fragment的创建和移除,但是这样会导致Fragment频繁的创建和销毁,对程序的性能具有极大影响。为了方便实现Fragment的创建和销毁时机,以及对Fragment实现向Activity一样的管理,我们可以使用Fragment的回退栈。
今天涉及的内容有:
- Fragment回退栈相关的几个重要方法
- Fragment回退栈管理类FragmentStackManager简介
- FragmentStackManager管理Fragment实例讲解
- 效果图
- FragmentStackManager源码
先上波效果图:
下面这张是FragmentThree返回到FragmentOne的所有操作:
1.gif
下面这张是FragmentThree关闭所有Fragment的所有操作:
2.gif
项目结构图如下:
image.png
一. Fragment回退栈相关的几个重要方法
Fragment回退栈管理相关的几个方法主要和 FragmentTransaction 及 FragmentManager相关,其中 FragmentTransaction 涉及到向回退栈中添加Fragment,以下给出代码示例:
FragmentManager manager= ((FragmentActivity)context).getSupportFragmentManager();
Fragment fragment=manager.findFragmentByTag(tag);
//添加fragment到回退栈
transaction.addToBackStack(tag);
//其他代码省略
//......
弹出栈顶最后一个Fragment(弹出后此Fragment会被销毁)
fragmentManager.popBackStack();
获取回退栈中Fragment个数
fragmentManager.getBackStackEntryCount();
销毁回退栈中部分Fragment
fragmentManager.popBackStackImmediate(name,flag);
这里对popBackStackImmediate方法参数做一个解释:
方法中第二个参数 flag 只能是 0 或者 1(POP_BACK_STACK_INCLUSIVE)
- 当第一个参数为 null,第二个参数为 0 时,会弹出栈顶的一个fragment
- 当第一个参数为 null,第二个参数为 1 (POP_BACK_STACK_INCLUSIVE)时,会清空回退栈中所有fragment
- 当第一个参数为fragment的tag,第二个参数为1(POP_BACK_STACK_INCLUSIVE)时,会弹出该状态(包括该状态)以上的所有状态
二. Fragment回退栈管理类FragmentStackManager简介
我将Fragment回退栈的相关方法封装到FragmentStackManager类中,现在对FragmentStackManager中一些方法做些简单介绍:
跳转Fragment界面时,添加fragment到回退栈中
/***
* 跳转fragmnet并添加到回退栈
*
* @param containerId 装fragment的控件id,一般是FrameLayout的id
* @param context 上下文
* @param tag fragment对应的tag
* @param bundle 传值用的bundle
* @param listener 创建一个frgmment实例的监听
* @return
*/
public Fragment startFragment(int containerId, Context context, String tag, Bundle bundle, OnCreateFragmentListener listener)
关闭当前Fragment
public void finish(Context context)
根据之前fragment界面的tag,返回到那个fragment界面并关闭当前Fragment和要返回fragment界面之间的fragment,包括关闭当前的fragment
/***
* 返回到指定已经打开的fragment,并关闭当前及当前与指定Fragment间的所有Fragment
* @param tag 需要返回到指定Fragment的tag
* 若你需要返回到FragmentOne,且FragmentOne的tag为“one”,则此处tag参数填“one”
* @param context
*/
public void goBackToFragmentByTag(String tag,Context context)
关闭所有Fragment
public void finishAllFragments(Context context)
获取回退栈中fragment个数
public int getFragmentSize(Context context)
获取回退栈中所有Fragment对应的tag的集合
public List<String> getFragmentTags(Context context)
三. FragmentStackManager管理Fragment实例讲解
下面来讲解下FragmentStackManager在实际中的使用。
创建三个Fragment:FragmentOne,FragmentTwo和 FragmentThree,每个Fragment中都是两个按钮,一个textview,按钮用于处理返回和跳转,textview用来显示当前是哪一个Fragment。
以FragmentOne为例,其对应的布局 fragment_one.xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:background="@color/white">
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="第一个Fragment"
app:layout_constraintHorizontal_bias="0.494"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="Button"
android:textAllCaps="false"
app:layout_constraintEnd_toStartOf="@+id/button2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
android:textAllCaps="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button"
app:layout_constraintTop_toTopOf="@+id/button" />
</androidx.constraintlayout.widget.ConstraintLayout>
FragmentOne的代码如下:
public class FragmentOne extends AppFragment {
private TextView mTv;
private Button mBtn;
private Button mBtn2;
private FragmentTwo mFragmentTwo;
@Override
public int getContentViewId() {
return R.layout.fragment_one;
}
@Override
public void initData() {
//初始化控件
initView();
}
private void initView(){
mTv=getView(R.id.tv);
mBtn=getView(R.id.button);
mBtn2=getView(R.id.button2);
mBtn.setText("返回");
mBtn2.setText("跳转fragment2");
}
@Override
public void setListener() {
mBtn.setOnClickListener(this);
mBtn2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
super.onClick(v);
switch (v.getId()) {
case R.id.button://返回
FragmentStackManager.getInstance().finish(mContext);
break;
case R.id.button2://跳转fragment2
mFragmentTwo= (FragmentTwo) FragmentStackManager.getInstance().startFragment(R.id.fr, mContext, "two", null, new FragmentStackManager.OnCreateFragmentListener() {
@Override
public Fragment createFragment() {
return new FragmentTwo();
}
});
break;
default:
break;
}
}
@Override
public void onDestroy() {
super.onDestroy();
LogUtil.i("========fragment1销毁=====");
}
}
其他Fragment逻辑相似,大体思路是,在MainActivity中点击按钮,跳转到FragmentOne,FragmentOne点击返回可以关闭当前Fragment到MainActivity中,点击右侧按钮可以跳转到FrgmentTwo,FragmentTwo中有两个按钮,一个用于关闭当前界面,一个用于跳转FrargmentThree,然后FragmentThree中两个按钮,一个用于关闭当前界面,返回到上一个Fragment界面,另一个按钮用作其他处理。
ok,现在让我们看看MainActivity中代码:
public class MainActivity extends AppFragActivity {
private TextView mTv;
private Button mBtn;
private Button mBtn2;
private FrameLayout mFrLayout;
private FragmentOne mFragmentOne;
@Override
public int getContentViewId() {
return R.layout.activity_main;
}
@Override
public void initData() {
initView();
mBtn.setText("跳转fragment");
mBtn2.setText("回退栈个数");
}
private void initView(){
mTv=getView(R.id.tv);
mBtn=getView(R.id.button);
mBtn2=getView(R.id.button2);
mFrLayout=getView(R.id.fr);
LogUtil.i("=====最新测试===1===");
}
@Override
public void setListener() {
mBtn.setOnClickListener(this);
mBtn2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
super.onClick(v);
switch (v.getId()) {
case R.id.button:
mFragmentOne= (FragmentOne) FragmentStackManager.getInstance().startFragment(R.id.fr, mContext, "one", null, new FragmentStackManager.OnCreateFragmentListener() {
@Override
public Fragment createFragment() {
return new FragmentOne();
}
});
break;
case R.id.button2:
//回退栈中fragment个数
int count=FragmentStackManager.getInstance().getFragmentSize(mContext);
LogUtil.i("=====回退栈中fragment个数===="+count);
List<String>fragmentTags=FragmentStackManager.getInstance().getFragmentTags(mContext);
//遍历fragment的tag
for (String tag : fragmentTags) {
LogUtil.i("====fragmentTag==="+tag);
}
break;
default:
break;
}
}
}
其中AppFragActivity 是封装的一个继承自AppCompatActivity的基类,类似于大家常用的BaseActivity,button用于跳转到FragmmentOne,button2用于统计回退栈中Fragment个数,并打印Fragment对应的tag。FragmentTwo中两个按钮事件代码如下:
public void onClick(View v) {
super.onClick(v);
switch (v.getId()) {
case R.id.button://返回
FragmentStackManager.getInstance().finish(mContext);
break;
case R.id.button2://跳转fragment3
mFragmentThree= (FragmentThree) FragmentStackManager.getInstance().startFragment(R.id.fr, mContext, "three", null, new FragmentStackManager.OnCreateFragmentListener() {
@Override
public Fragment createFragment() {
return new FragmentThree();
}
});
break;
default:
break;
}
}
一个用于关闭当前界面,一个用于跳转到FragmentThree。
在FragmentThree中两个按钮事件如下:
@Override
public void onClick(View v) {
super.onClick(v);
switch (v.getId()) {
case R.id.button://返回
FragmentStackManager.getInstance().finish(mContext);
break;
case R.id.button2://跳转到fragment1
//返回到FragmentOne
FragmentStackManager.getInstance().goBackToFragmentByTag("one",mContext);
// //关闭所有Fragment
// FragmentStackManager.getInstance().finishAllFragments(mContext);
break;
default:
break;
}
}
button按钮用于关闭当前Fragment,button2中有两个方法,一个用于返回到FragmnetOne并关闭faragmmentTwo和FragmentThree,另一个方法用于关闭所有fragment。
四. 效果图
下面这张是FragmentThree返回到FragmentOne的所有操作:
1.gif
下面这张是FragmentThree关闭所有Fragment的所有操作:
2.gif
五. FragmentStackManager源码
下面给出 FragmentStackManager管理类代码: