从源码的角度分析Fragment

1.我们最常用的有:①ViewPager + Fragment;②ViewGroup + Fragment ;③TabHost+Fragment
2.今天主要讲ViewGroup+Fragment

  • 2.1Fragment的添加
        // 加载第一个Fragment  兼容11以下的版本
        FragmentManager fragmentManager = getSupportFragmentManager();
        // 把第一个Fragment HomeFragment加载进来
        mVideoFragment = new VideoFragment();
        // 开启事物
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        // 第一个参数是Fragment的容器id,需要添加的Fragment
        transaction.add(R.id.fl_main_content, mVideoFragment);
        // 一定要commit
        transaction.commit();
  • 2.2fragment的替换
      FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        if (mAudioFragment == null) {
            mAudioFragment = new AudioFragment();
        }
        //替换
        transaction.replace(R.id.fl_main_content, mAudioFragment);
        //一定要提交
        transaction.commit();

分析现象:每次切换都会重新刷新页面,提交数据

3.Fragment源码分析
3.1Fragment.add方法源码分析
3.1.1getSupportFragmentManager源码分析

  //首先看我们写的代码
 FragmentManager fragmentManager = getSupportFragmentManager();

  public FragmentManager getSupportFragmentManager() {
        return mFragments.getSupportFragmentManager();
    }

   public FragmentManager getSupportFragmentManager() {
        return mHost.getFragmentManagerImpl();
    }

   FragmentManagerImpl getFragmentManagerImpl() {
        return mFragmentManager;
    }
    //最终返回的是FragmentManagerImpl 
final FragmentManagerImpl  mFragmentManager = new FragmentManagerImpl();

3.1.2看FragmentManagerImpl 中的beginTransaction

   @Override
    public FragmentTransaction beginTransaction() {
        return new BackStackRecord(this);
    }
    //最终是将FragmentManagerImpl进行赋值
   public BackStackRecord(FragmentManagerImpl manager) {
         mManager = manager;
    }

3.1.3BackStackRecord中的add方法

    // transaction.add(R.id.fl_main_content, mVideoFragment);
    @Override
    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) {
        //mVideoFragment获得类的对象
        final Class fragmentClass = fragment.getClass();
        //返回该类的修饰符,如public
        final int modifiers = fragmentClass.getModifiers();
        //isAnonymousClass该类是不是内部类   isMemberClass是不是成员类
        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.");
        }
       //由上面可以知道是我们自己开启事务后传来的值
        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;
        }
        //R.id.fl_main_content
        if (containerViewId != 0) {
            if (containerViewId == View.NO_ID) {
                throw new IllegalArgumentException("Can't add fragment "
                        + fragment + " with tag " + tag + " to container view with no id");
            }
            if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
                throw new IllegalStateException("Can't change container ID of fragment "
                        + fragment + ": was " + fragment.mFragmentId
                        + " now " + containerViewId);
            }
            //最终将自己的id传给fragment的参数中
            fragment.mContainerId = fragment.mFragmentId = containerViewId;
        }
        //设置参数
        Op op = new Op();
        op.cmd = opcmd;
        op.fragment = fragment;
        addOp(op);
    }

由上面我们可以知道add只是添加了相关参数

3.3.4commit源码分析:还是在BackStackRecord中

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

   int commitInternal(boolean allowStateLoss) {
        if (mCommitted) throw new IllegalStateException("commit already called");
        if (FragmentManagerImpl.DEBUG) {
            Log.v(TAG, "Commit: " + this);
            LogWriter logw = new LogWriter(TAG);
            PrintWriter pw = new PrintWriter(logw);
            dump("  ", null, pw, null);
            pw.close();
        }
        mCommitted = true;
        if (mAddToBackStack) {
            mIndex = mManager.allocBackStackIndex(this);
        } else {
            mIndex = -1;
        }
        //直接看这个
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
        if (!allowStateLoss) {
            checkStateLoss();
        }
        synchronized (this) {
            if (mDestroyed || mHost == null) {
                throw new IllegalStateException("Activity has been destroyed");
            }
            if (mPendingActions == null) {
                mPendingActions = new ArrayList<>();
            }
            mPendingActions.add(action);
            //看这个
            scheduleCommit();
        }
    }

    private void scheduleCommit() {
        synchronized (this) {
            boolean postponeReady =
                    mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
            boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
            if (postponeReady || pendingReady) {
              //异步的方法,看mExecCommit
                mHost.getHandler().removeCallbacks(mExecCommit);
                mHost.getHandler().post(mExecCommit);
            }
        }
    }

    Runnable mExecCommit = new Runnable() {
        @Override
        public void run() {
            execPendingActions();
        }
    };

 public boolean execPendingActions() {
        ensureExecReady(true);

        boolean didSomething = false;
        while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
            mExecutingActions = true;
            try {
                optimizeAndExecuteOps(mTmpRecords, mTmpIsPop);
            } finally {
                cleanupExec();
            }
            didSomething = true;
        }
           //看这个
        doPendingDeferredStart();

        return didSomething;
    }


void doPendingDeferredStart() {
        if (mHavePendingDeferredStart) {
            boolean loadersRunning = false;
            for (int i = 0; i < mActive.size(); i++) {
                Fragment f = mActive.get(i);
                if (f != null && f.mLoaderManager != null) {
                    loadersRunning |= f.mLoaderManager.hasRunningLoaders();
                }
            }
            if (!loadersRunning) {
                mHavePendingDeferredStart = false;
                startPendingDeferredFragments();
            }
        }
    }

void startPendingDeferredFragments() {
        if (mActive == null) return;

        for (int i=0; i<mActive.size(); i++) {
            Fragment f = mActive.get(i);
            if (f != null) {
                performPendingDeferredStart(f);
            }
        }
    }

    public void performPendingDeferredStart(Fragment f) {
        if (f.mDeferStart) {
            if (mExecutingActions) {
                // Wait until we're done executing our pending transactions
                mHavePendingDeferredStart = true;
                return;
            }
            f.mDeferStart = false;
            //移动到当前状态
            moveToState(f, mCurState, 0, 0, false);
        }
    }

3.1.5最终会走到moveToState这个方法,方法太长就直接找有用的


 void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {

    //没有添加修改当前状态为创建状态
   if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
            newState = Fragment.CREATED;
        }

...
    switch (f.mState) {
     case Fragment.INITIALIZING:
     ....
       //fragment的onAttach方法
      f.onAttach(mHost.getContext());
      ...
    if (!f.mRetaining) {
     //调用framgment的create方法
      f.performCreate(f.mSavedFragmentState);
      dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
      }
      if (f.mFromLayout) {
      //最终调用的是我们自己复写的onCreateView方法
       f.mView = f.performCreateView(f.getLayoutInflater(
                 f.mSavedFragmentState), null, f.mSavedFragmentState);
        }
      ....

   }
  case Fragment.CREATED:{
      if (newState > Fragment.CREATED) {
         //findviewByid返回一个ViewGroup.也就是我们自己写的FrameLayout
          mContainer.onFindViewById(f.mContainerId);

        }
        //又会调用我们复写的onCreateView  难道自己定义fragment中的onCreateView
   f.mView = f.performCreateView(f.getLayoutInflater(
         f.mSavedFragmentState), container, f.mSavedFragmentState);
         //添加进去
        if (container != null) {
           container.addView(f.mView);
         }
     }
   }
}

3.1.6performCreateView源码分析

       View performCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.noteStateNotSaved();
        }
        return onCreateView(inflater, container, savedInstanceState);


 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        return null;
    }

3.2fragment的replace方法源码分析:BackStackRecord

 @Override
    public FragmentTransaction replace(int containerViewId, Fragment fragment) {
        return replace(containerViewId, fragment, null);
    }

@Override
    public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
        if (containerViewId == 0) {
            throw new IllegalArgumentException("Must use non-zero containerViewId");
        }
          //与上面的add的调用方法一模一样,只是参数变了OP_REPLACE
        doAddOp(containerViewId, fragment, tag, OP_REPLACE);
        return this;
    }

3.2.1直接搜索OP_REPLACE

 case OP_REPLACE: {
                    Fragment f = op.fragment;
                    int containerId = f.mContainerId;
                    boolean alreadyAdded = false;
                    for (int i = added.size() - 1; i >= 0; i--) {
                     //遍历获得已经有的fragment
                        Fragment old = added.get(i);
                        if (old.mContainerId == containerId) {
                            if (old == f) {
                                alreadyAdded = true;
                            } else {
                                Op removeOp = new Op();
                                removeOp.cmd = OP_REMOVE;
                                removeOp.fragment = old;
                                removeOp.enterAnim = op.enterAnim;
                                removeOp.popEnterAnim = op.popEnterAnim;
                                removeOp.exitAnim = op.exitAnim;
                                removeOp.popExitAnim = op.popExitAnim;
                                mOps.add(opNum, removeOp);
                                //移除已经有的fragment
                                added.remove(old);
                                opNum++;
                            }
                        }
                    }
                    if (alreadyAdded) {
                        mOps.remove(opNum);
                        opNum--;
                    } else {
                        op.cmd = OP_ADD;
                        //又走向了add得到方法
                        added.add(f);
                    }
                }

replace()的源码就是把之前的移除,会重新执行Fragment生命周期, 会重新绘制界面

解决思路

    FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        if (mVideoFragment == null) {
            mVideoFragment = new VideoFragment();
        }
        //首先隐藏所有的fragment
        List<Fragment> fragments = fragmentManager.getFragments();
        for (Fragment fragment : fragments) {
            transaction.hide(fragment);
        }
        //如果没有则add否则显示
        if(!fragments.contains(mVideoFragment)){
            transaction.add(R.id.fl_main_content,mVideoFragment);
        }else{
            transaction.show(mVideoFragment);
        }
        //替换
        //transaction.replace(R.id.fl_main_content, mVideoFragment);
        transaction.commit();

我写过一篇文章对fragment的封装,大家可以去看下
http://blog.csdn.net/qq_24675479/article/details/79327825

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值