当前位置: 首页 > article >正文

Android:FragmentTransaction

上一篇Android:FragmentTransaction我们大概介绍了FragmentManager的大致工作流程,知道了每个动作都会添加到Op队列里,并由FragmentTransaction进行管理,那么我们就来看看FragmentTransaction的具体内容。

首先FragmentTransaction中定义了每个动作的常量值。

    static final int OP_NULL = 0;
    static final int OP_ADD = 1;
    static final int OP_REPLACE = 2;
    static final int OP_REMOVE = 3;
    static final int OP_HIDE = 4;
    static final int OP_SHOW = 5;
    static final int OP_DETACH = 6;
    static final int OP_ATTACH = 7;
    static final int OP_SET_PRIMARY_NAV = 8;
    static final int OP_UNSET_PRIMARY_NAV = 9;
    static final int OP_SET_MAX_LIFECYCLE = 10;

在这些值里面,我们看到了非常熟悉的一些操作,比如add,hide,replace等,每个动作都对应一个值。

有了值,就会为每个动作分配定义一个对象。内部类Op。

    static final class Op {
        //每个动作对应的命令数值
        int mCmd;
        //要操作的那个fragment
        Fragment mFragment;
        //进入动画
        int mEnterAnim;
        //退出时动画
        int mExitAnim;
        int mPopEnterAnim;
        int mPopExitAnim;
        //声明周期状态
        Lifecycle.State mOldMaxState;
        Lifecycle.State mCurrentMaxState;
    }

那每个动作是如何添加到事务的呢?当我们调用事务的add,hide,show等操作时,从前面文章知道:

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();

这个transaction其实是BackStackRecord对象,所以会调用BackStackRecord中对应的方法,比如hide操作。

//BackStackRecord.java

    public FragmentTransaction hide(@NonNull Fragment fragment) {
        ......
        //调用父类
        return super.hide(fragment);
    }

//父类:FragmentTransaction.java

    public FragmentTransaction hide(@NonNull Fragment fragment) {
        addOp(new Op(OP_HIDE, fragment));

        return this;
    }

最终调用父类的addOp方法,创建了一个Op对象,并传入OP_HIDE值和要操作的Fragment对象,然后将其添加到mOps列表中。

    ArrayList<Op> mOps = new ArrayList<>();

    void addOp(Op op) {
        mOps.add(op);
        op.mEnterAnim = mEnterAnim;
        op.mExitAnim = mExitAnim;
        op.mPopEnterAnim = mPopEnterAnim;
        op.mPopExitAnim = mPopExitAnim;
    }

我们在添加fragment到事务时,add方法有两个重载方法。

transaction.add(f1,"f1");
transaction.add(R.id.layout_f,f1,"f1");

一个是不传容器id,一个需要传,第一个方法,其实就是调用第二个方法,然后id传0。

    public FragmentTransaction add(@NonNull Fragment fragment, @Nullable String tag)  {
        doAddOp(0, fragment, tag, OP_ADD);
        return this;
    }

对于第二个方法,我们来看看。

void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
    //反射
    final Class<?> fragmentClass = fragment.getClass();
    final int modifiers = fragmentClass.getModifiers();
    //检查fragment是否是匿名类,是不是public的,是不是静态类,是不是嵌套类等
    if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
            || (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
        throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName()
                + " must be a public static class to be  properly recreated from"
                + " instance state.");
    }
    //如果有标签tag
    if (tag != null) {
        //检查tag,不允许修改已经存在的tag
        if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
            throw new IllegalStateException("Can't change tag of fragment "
                    + fragment + ": was " + fragment.mTag
                    + " now " + tag);
        }
        fragment.mTag = tag;
    }
    //如果设置里容器Id
    if (containerViewId != 0) {
        //如果没有为容器设置ID
        if (containerViewId == View.NO_ID) {
            throw new IllegalArgumentException("Can't add fragment "
                    + fragment + " with tag " + tag + " to container view with no id");
        }
        //如果fragment已经有容器Id了,不允许变更
        if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
            throw new IllegalStateException("Can't change container ID of fragment "
                    + fragment + ": was " + fragment.mFragmentId
                    + " now " + containerViewId);
        }
        fragment.mContainerId = fragment.mFragmentId = containerViewId;
    }
    //添加Op到队列
    addOp(new FragmentTransaction.Op(opcmd, fragment));
}

代码做了注释,就不在具体描述了。

再来看attach和detach方法,detach会将fragment从UI界面移除,即使调用show也无法再次显示出来。调用attach后,fragment会重新显示在界面上。

        findViewById(R.id.tv_1).setOnClickListener((v -> {
            FragmentTransaction t = fragmentManager.beginTransaction();
            t.detach(f1);
            t.commitNow();
        }));
        findViewById(R.id.tv_2).setOnClickListener((v -> {
            FragmentTransaction t = fragmentManager.beginTransaction();
            t.attach(f1);
            t.commitNow();
        }));


http://www.kler.cn/a/148777.html

相关文章:

  • python爬虫(二)爬取国家博物馆的信息
  • nVisual自定义工单内容
  • Linux 下 mysql 9.1 安装设置初始密码 【附脚本】
  • 基于Python 和 pyecharts 制作招聘数据可视化分析大屏
  • 学习日志010--python异常处理机制与简单文件操作
  • 项目风险管理的3大要素
  • a-range-picker 时间选择器的默认日期显示,日期格式化
  • OMP: Error #15: Initializing libiomp5md.dll
  • C语言——求π的近似值
  • 第八节HarmonyOS @Component自定义组件的生命周期
  • 【Qt之QSqlTableModel】介绍及使用
  • u-popup组件在UniApp中的讲解
  • Unity 关于生命周期函数的一些认识
  • 【创建一个组件并通过npm让其他人安装和调用】
  • 【数据结构】排序效率最优解之一:二叉树-堆
  • .netcore 获取appsettings
  • Leetcode—58.最后一个单词的长度【简单】
  • Linux处理文件常见命令
  • 基于合成数据的行人检测AI模型训练
  • 火柴人版王者-Java
  • java使用freemarker模板生成html,再生成pdf
  • 利用Spring Boot构建restful web service的详细流程
  • Nginx系列-正向代理和反向代理
  • Vue3+java开发组队功能
  • 【hive-design】hive架构详解:描述了hive架构,hive主要组件的作用、hsql在hive执行过程中的底层细节、hive各组件作用
  • Java中关于ArrayList集合的练习题