FragmentManager及FragmentTransaction浅析

前一阵子和朋友聊技术的时候在讨论fragment的实现的时候,突发奇想想看看他们对谷歌是如何实现fragment的,我的看法是可以通过对viewgroup的addview操作来实现fragment的添加以及别的操作,下面进入正题。
先在这里给大家介绍一个网站:https://searchcode.com/,这个网站可以通过类名直接去找源码。
首先我们都知道FragmentManager是谷歌提供给我们的fragment的管理类,可以通过这个类去执行fragment的相关操作。但是仔细观察源码我们就会发现FragmentManager(下文会用fm代替)是一个抽象类,他的实现类是FragmentManagerImpl。之后根据上面给的网站去检索这个类。

final class FragmentManagerImpl extends FragmentManager{
    ArrayList mActive;
    FragmentActivity mActivity;
    //保存fragment
    ArrayList mAdded;
    //保存FragmentTransaction
    ArrayList mAvailBackStackIndices;
    ArrayList mAvailIndices;
    ArrayList mBackStack;
    ArrayList mBackStackChangeListeners;
    ArrayList mBackStackIndices;
    ArrayList mCreatedMenus;
}

从代码上我们可以看出来,这个类里面实例化了几个LIST去保存fragment,同时,会传入activity属性。根据这个FragmentManager暴露的方法我们也可以简单的猜测到其作用是用来保存fragment实例,以方便下次调用。
之后我们分析下我们执行fragment操作的关键类FragmentTransaction(下文用ft来代替),同样的这个类也是一个抽象类,他的实例是BackStackRecord,他在实例化的时候会传入当前的FragmentManager。
首先我们先看看调用这个BackStackRecord的add方法。

    public FragmentTransaction add(int containerViewId, Fragment fragment) {
        doAddOp(containerViewId, fragment, null, OP_ADD);
        return this;
    }

    private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
        fragment.mFragmentManager = mManager;

        if (tag != null) {
            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;
        }

        if (containerViewId != 0) {
            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 op = new Op();
        op.cmd = opcmd;
        op.fragment = fragment;
        addOp(op);
    }

根据这两段代码,可以看出来当我们可以看出来当我们通过ft的添加指令之后,只是在ft的执行队列中增加了一个执行动作而已。
当完成这些添加动作之后我们会去执行ft的commit操作。那么commit到底执行了些什么。

    public int commit() {
        return commitInternal(false);
    }

    public int commitAllowingStateLoss() {
        return commitInternal(true);
    }

    int commitInternal(boolean allowStateLoss) {
        if (mCommitted) throw new IllegalStateException("commit already called");
        if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Commit: " + this);
        mCommitted = true;
        if (mAddToBackStack) {
            mIndex = mManager.allocBackStackIndex(this);
        } else {
            mIndex = -1;
        }
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

这段代码粗浅的看,好像看不出到底做了哪些操作,这个时候我们要回到fm类中去看看调用的方法。

    public int allocBackStackIndex(BackStackRecord backstackrecord) {
        this;
        JVM INSTR monitorenter ;
        int j;
        if(mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
            if(mBackStackIndices == null)
                mBackStackIndices = new ArrayList();
            int i = mBackStackIndices.size();
            if(DEBUG)
                Log.v("FragmentManager", (new StringBuilder()).append("Setting back stack index ").append(i).append(" to ").append(backstackrecord).toString());
            mBackStackIndices.add(backstackrecord);
            j = i;
        } else {
            int k = ((Integer)mAvailBackStackIndices.remove(-1 + mAvailBackStackIndices.size())).intValue();
            if(DEBUG)
                Log.v("FragmentManager", (new StringBuilder()).append("Adding back stack index ").append(k).append(" with ").append(backstackrecord).toString());
            mBackStackIndices.set(k, backstackrecord);
            j = k;
        }
        return j;
    }

首先是这个方法,这个是在fm的list里面加入ft这个类,添加缓存。

    public void enqueueAction(Runnable runnable, boolean flag) {
        if(!flag)
            checkStateLoss();
        this;
        JVM INSTR monitorenter ;
        if(mActivity == null)
            throw new IllegalStateException("Activity has been destroyed");
        break MISSING_BLOCK_LABEL_33;
        Exception exception;
        exception;
        throw exception;
        if(mPendingActions == null)
            mPendingActions = new ArrayList();
        //核心部分代码
        mPendingActions.add(runnable);
        if(mPendingActions.size() == 1) {
            mActivity.mHandler.removeCallbacks(mExecCommit);
            mActivity.mHandler.post(mExecCommit);
        }
        this;
        JVM INSTR monitorexit ;
    }

这个是最后一个执行的方法,从中我们可以看出回去调用ft的runnable接口。并让handler去执行这个runnbale方法。
那么最关键的地方来了,runnable方法到底执行了什么代码指令呢。
这里我们只介绍其中一种,就是add属性,下面我会把代码截图上传。

 public void run() {
        if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this);

        if (mAddToBackStack) {
            if (mIndex < 0) {
                throw new IllegalStateException("addToBackStack() called after commit()");
            }
        }

        bumpBackStackNesting(1);

        Op op = mHead;
        while (op != null) {
            switch (op.cmd) {
                case OP_ADD: {
                    Fragment f = op.fragment;
                    f.mNextAnim = op.enterAnim;
                    //调用了fragmentmanager的addfragment方法
                    mManager.addFragment(f, false);
                } break;
                .......
            }
       }
 }

可以看出主要还是调用了fm里面的方法,ft并没有产生什么别的操作。
那么回到fm里面的addfragment,因为那边代码太长了,所以我只会把核心部分的代码贴出来。
首先要讲的是,无论是那种方式添加fragment的,最终对于fm来说都只是调用了其中的moveToState方法。这个方法会去加载一些我们在fragment中很熟悉的方法。

  void moveToState(int i, int j, int k, boolean flag) {
   if(fragment.mSavedFragmentState != null) {
            fragment.mSavedViewState = fragment.mSavedFragmentState.getSparseParcelableArray("android:view_state");
            fragment.mTarget = getFragment(fragment.mSavedFragmentState, "android:target_state");
            if(fragment.mTarget != null)
                fragment.mTargetRequestCode = fragment.mSavedFragmentState.getInt("android:target_req_state", 0);
            fragment.mUserVisibleHint = fragment.mSavedFragmentState.getBoolean("android:user_visible_hint", true);
            if(!fragment.mUserVisibleHint) {
                fragment.mDeferStart = true;
                if(i > 3)
                    i = 3;
            }
        }
        fragment.mActivity = mActivity;
        fragment.mFragmentManager = mActivity.mFragments;
        fragment.mCalled = false;
        fragment.onAttach(mActivity);
        mActivity.onAttachFragment(fragment);
        if(!fragment.mRetaining) {
            fragment.mCalled = false;
        fragment.onCreate(fragment.mSavedFragmentState);
        fragment.mRetaining = false;
        if(fragment.mFromLayout) {
            fragment.mView = fragment.onCreateView(fragment.getLayoutInflater(fragment.mSavedFragmentState), null, fragment.mSavedFragmentState);
            if(fragment.mView != null) {
                fragment.mInnerView = fragment.mView;
                fragment.mView = NoSaveStateFrameLayout.wrap(fragment.mView);
                if(fragment.mHidden)
                    fragment.mView.setVisibility(8);
                fragment.onViewCreated(fragment.mView, fragment.mSavedFragmentState);
            } else {
                fragment.mInnerView = null;
            }
        }
  }

这段代码中我们可以发现,fragment中,所有方法的执行顺序应该是onAttach
->onCreate->onCreateView。
从上面这段代码可以看出当我们在fragment中完成了view的生成之后,代码会继续向下执行,首先会先去实例化出对应的viewgroup,之后再将fragment生成的view存放到这个viewgroup中去。
从这里就能简单的知道fragment以及fm ft的运行方式。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值