FragmentManager源码简单分析

FragmentManager源码简单分析

我们对Fragment的用法已经再熟悉不过了, 对Fragment不了解建议去了解了解, 毕竟是基础; 博客对Fragment的使用方法讲解的非常之多, 但是对源码分析的却寥寥无几, 最近公司项目需要一个框架, 跟Activity 和 Fragment 比较像, 所以选择了Fragment来参考.

废话不多说, 下面我们一步一步通过使用Fragment的步骤来分析源码:

在Activity中 我们通过 getFragmentManager()获取到一个 FragmentManager对象,这是一个抽象内, 真正使用的FragmentManager是它的实现类FragmentManagerImpl

final class FragmentManagerImpl extends FragmentManager {}

然后我们会通过 FragmentManager.beginTransaction() 来获取一个FragmentTransaction对象, 我们对Fragment的add() remove() show() 等操作都是通过这个对象来完成的.

    public FragmentTransaction beginTransaction() {
        return new BackStackRecord(this);
    }

我们看到这里返回了一个 BackStackRecord对象, 并把FragmentManager自己作为构造传递过去, 这个对象肯定就是 FragmentTransaction 的子类, 从名字可以看去就是对Fragment的一个记录器.

然后我们找一个最熟悉的方法来分析, add() 来添加一个Fragment.

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

这里调用了doAddOp() 方法,并指定命令(操作) 为 OP_ADD, 我们来看看这里面干了什么玩意.

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

 /**
    这里一小段代码主要做了一些判断 判断当前的tag, containerViewId 是   否和 Fragment中的tag, containerViewId是否相同
 **/
        Op op = new Op();
        op.cmd = opcmd;
        op.fragment = fragment;
        addOp(op);
    }

这里new了一个 op对象, 并将操作命令赋值给op.cmd, 当前要操作的Fragment赋值给op.Fragment, 我们看看OP是个什么鬼

    static final class Op {
        Op next;
        Op prev;
        int cmd;
        Fragment fragment;
        int enterAnim;
        int exitAnim;
        int popEnterAnim;
        int popExitAnim;
        ArrayList<Fragment> removed;
    }

这个类很简单, 使用了一个链表的结构, 将一些属性进行了封装. 上面的方法最后调用了addOp(op) 的方法, 不多说, 过去看看干了什么.

    void addOp(Op op) {
        if (mHead == null) {
            mHead = mTail = op;
        } else {
            op.prev = mTail;
            mTail.next = op;
            mTail = op;
        }
        op.enterAnim = mEnterAnim;
        op.exitAnim = mExitAnim;
        op.popEnterAnim = mPopEnterAnim;
        op.popExitAnim = mPopExitAnim;
        mNumOp++;
    }

好失望, 貌似什么也没有干, 就是将OP对象的属性进行赋值, Y_Y 等等, 不要忘了, 在我们对Fragment操作后, 都会调用 FragmentTransaction.commit()方法, 赶紧过去瞅瞅.

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

这里调用了 commitInternal(false) .

 int commitInternal(boolean allowStateLoss) {
      /**
       没用的代码干掉
       **/

        mCommitted = true;
        if (mAddToBackStack) {
            mIndex = mManager.allocBackStackIndex(this);
        } else {
            mIndex = -1;
        }
        //mManager 就是FragmentManager对象, 看方法名Action应该就是处理Fragment的操作
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

回到FragmentManagerImpl, 找到 enqueueAction()方法

 public void enqueueAction(Runnable action, boolean allowStateLoss)

第一个参数是一个Runnable对象, 而当时调用的时候使用的是 this, 也就是 BackStackRecord自己,回过头看看 确实实现了 Runnable接口; 第二个参数不用管, 当时传过来的是false. 看看具体代码

    public void enqueueAction(Runnable 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<Runnable>();
            }
            //将当前的Runnable对象,也就是 BackStackRecord添加到一个集合中去.
            mPendingActions.add(action);
            if (mPendingActions.size() == 1) {
                mHost.getHandler().removeCallbacks(mExecCommit);
                //是用handler.post() 发出了一个消息
                mHost.getHandler().post(mExecCommit);
            }
        }
    }

看看 mExecCommit是一个什么玩意

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

内部执行了 execPendingActions() 方法

这里面的代码比较多, 节省空间 抽出核心代码

//看着像一个死循环, 不要被吓到 下面还有个break呢. 
while (true) {
     int numActions; 
     synchronized (this) {
         if (mPendingActions == null || mPendingActions.size() == 0) {
             break;
         }
         numActions = mPendingActions.size();
         //这里重新使用了一个数组对 Runnable对象 也就是BackStackRecord进行存储
         if (mTmpActions == null || mTmpActions.length < numActions) {
             mTmpActions = new Runnable[numActions];
         }
         mPendingActions.toArray(mTmpActions);
         //清空就满足上面的break条件了
         mPendingActions.clear();
         mHost.getHandler().removeCallbacks(mExecCommit);
     }

     mExecutingActions = true;
     for (int i=0; i<numActions; i++) {
     //调用了run()方法
         mTmpActions[i].run();
         mTmpActions[i] = null;
     }
     mExecutingActions = false;
     didSomething = true;
 }

让我们回去看看 BackStackRecord中 的run() 方法做了什么鬼操作

//这里又是一堆代码, 但是看到这里貌似已经豁然开朗了. 我们来挑一个来看看
public void run() {
 Op op = mHead;
    while (op != null) {
         switch (op.cmd) {
             case OP_ADD: {
                 Fragment f = op.fragment;
                 f.mNextAnim = op.enterAnim;
                 mManager.addFragment(f, false);
             }
             break;
         }
         op = op.next;
    }
}

这里依然是一个while循环, 也就是对链表 OP对象 逐一进行处理, 挑了我们眼熟的OP_ADD, 是不是很眼熟, 这里又回到FragmentManager中调用了 addFragment()方法, 名字已经很明显的暴露出它要干什么了, 不过也是挺绕的

public void addFragment(Fragment fragment, boolean moveToStateNow) {
     if (mAdded == null) {
         mAdded = new ArrayList<Fragment>();
     }
     if (DEBUG) Log.v(TAG, "add: " + fragment);
     makeActive(fragment);
     if (!fragment.mDetached) {
         if (mAdded.contains(fragment)) {
             throw new IllegalStateException("Fragment already added: " + fragment);
         }
         mAdded.add(fragment);
         fragment.mAdded = true;
         fragment.mRemoving = false;
         if (fragment.mHasMenu && fragment.mMenuVisible) {
             mNeedMenuInvalidate = true;
         }
         if (moveToStateNow) {
             //这里最后调用了moveToState()方法
             moveToState(fragment);
         }
     }
 }
    void moveToState(Fragment f) {
       //调用了5个参数的方法
        moveToState(f, mCurState, 0, 0, false);
    }
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
            //这里的代码真是太多了!!! Y_Y就不贴了 
}

至此Fragment的生命周期的方法调用都是在上面这个方法( moveToState ) 中操作的, 应该是使用了状态模式, 看的我晕晕乎乎的.

看的源码比较少, 有什么不对的地方还需要大家提提意见, 看源码其实挺烦的, 有好多操作都不明白是怎么回事, 但是还是得硬着头皮看
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值