本文介绍: 上一篇我们大概介绍了FragmentManager的大致工作流程,知道了每个动作都会添加到Op队列里,并由FragmentTransaction进行管理,那么我们就来看看FragmentTransaction的具体内容。最终调用父类addOp方法创建了一个Op对象,并传入OP_HIDE值和要操作的Fragment对象然后将其添加mOps列表中。在这些值里面,我们看到了非常熟悉的一些操作,比如addhidereplace等,每个动作都对应一个值。有了值,就会为每个动作分配定义一个对象

上一篇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;

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

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

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

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

        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() &amp;&amp; !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 &amp;&amp; !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 &amp;&amp; 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();
        }));

原文地址:https://blog.csdn.net/bdmh/article/details/134669296

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_5059.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注