四大组件

Fragment(11)——回退栈管理

2019-08-12  本文已影响0人  奔跑的佩恩

前言

在Fragment的使用过程中,我们经常会遇到Fragment的启动和关闭的问题,我们当然可以使用add及remove系列方法来实现Fragment的创建和移除,但是这样会导致Fragment频繁的创建和销毁,对程序的性能具有极大影响。为了方便实现Fragment的创建和销毁时机,以及对Fragment实现向Activity一样的管理,我们可以使用Fragment的回退栈。

今天涉及的内容有:

  1. Fragment回退栈相关的几个重要方法
  2. Fragment回退栈管理类FragmentStackManager简介
  3. FragmentStackManager管理Fragment实例讲解
  4. 效果图
  5. 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)

二. 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管理类代码:

上一篇下一篇

猜你喜欢

热点阅读