从源码来看Fragment的生命周期(一)

请尊重原创,转载请注明出处【tianyl_Melody】的博客,http://blog.csdn.net/tianyl_melodie/article/details/53563701

1、说明

在Android中,除了Activity之外,另外一个用得最多的,就要数我们的Fragment了,看完了Activity的源码,接下来就再看Fragment的源码,来看看它与Activity有哪些不同。当然为了减少偏差,这里我使用的是Android6.0的源码(当然其他版本相差也不会太大)。
首先就从Fragment.java这个文件开始看起吧,打开Fragment.java这个文件,我们会发现这个文件中,除了定义Fragment这个类之外,还定义了另外的几个类。

2、FragmentState

首先定义的就是FragmentState这个类,根据这个类的名字,我们就能够看出来,它应该是用来保存Fragment信息的。看一下它的两个构造方法,基本和我们想得一样,在方法中设置一些Fragment信息,这里就不展开讨论了。

final class FragmentState implements Parcelable

public FragmentState(Fragment frag) {
        mClassName = frag.getClass().getName();
        mIndex = frag.mIndex;
        mFromLayout = frag.mFromLayout;
        mFragmentId = frag.mFragmentId;
        mContainerId = frag.mContainerId;
        mTag = frag.mTag;
        mRetainInstance = frag.mRetainInstance;
        mDetached = frag.mDetached;
        mArguments = frag.mArguments;
    }
    public FragmentState(Parcel in) {
        mClassName = in.readString();
        mIndex = in.readInt();
        mFromLayout = in.readInt() != 0;
        mFragmentId = in.readInt();
        mContainerId = in.readInt();
        mTag = in.readString();
        mRetainInstance = in.readInt() != 0;
        mDetached = in.readInt() != 0;
        mArguments = in.readBundle();
        mSavedFragmentState = in.readBundle();
    }

3、Fragment

除了FragmentState这个类之外,就是Fragment这个类了,首先看Fragment这个类的的定义:

public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener

显然,相比于Activity,Fragment就少实现了很多个接口。仅有的两个接口,一个是ComponentCallbacks2用来提供给开发人员管理内存,OnCreateContextMenuListener用来监听自定义菜单的。相比于Activity实现的接口,Fragment就明显要寒酸了许多。

既然从接口找不到信息,那么就只能看Fragment中的内容了,通过查看Fragment,发现里面有几个很特别的成员对象。

FragmentManagerImpl mFragmentManager;
// Activity this fragment is attached to.
Activity mActivity;
// Private fragment manager for child fragments inside of this one.
FragmentManagerImpl mChildFragmentManager;
// If this Fragment is contained in another Fragment, this is that container.
Fragment mParentFragment;

显然,每一个Fragment都会持有它依附的Activity的对象实例,那么另外几个都是干什么的呢?
其实在Fragment中,都会保存一个FragmentManagerImpl和mChildFragmentManager,用来在管理生命周期的时候一起调用,这在后面的生命周期中会说到。

4、FragmentManager

刚才在Fragment中我们看到了他会持有两个FragmentManagerImpl对象,一个是它自己的,另外一个通知名字我们判断是它子Fragment,现在我们就通过看FragmentManagerImpl,来了解这两个对象在Fragment中起着什么样的作用。
通过索引我们找到FragmentManager.java这个文件,发现它里面定义了三个类,分别是FragmentManager、FragmentManagerState和FragmentManagerImpl和一个接口FragmentContainer。

①FragmentManager
通过定义的描述,它是一个抽象类,看名字FragmentManagerImpl显然就是它的实现类。和我们之前看到的Context和ContextImpl很像。它里面定义了许多方法,这里就不全部列举了。
②FragmentManagerState
看名字和FragmentState很像,看它的成员变量:

FragmentState[] mActive;
int[] mAdded;
BackStackState[] mBackStack;

很明显是用来保存Fragment的信息用的,看里面的FragmentState数组,应该就是用来保存不同Fragment的FragmentState。
③FragmentContainer
这个接口的方法很少,根据注释描述,用来提供给FragmentManagerImpl回调的容器,那么等下就从FragmentManagerImpl中看它具体的作用吧。

interface FragmentContainer {
    public View findViewById(int id);
}

5、FragmentManagerImpl

FragmentManagerImpl是FragmentManager.java这个文件中最长的一个类了,对Fragment的管理的实现都应该在这个类当中,看这个类的定义:

final class FragmentManagerImpl extends FragmentManager

在Android22的代码里,FragmentManagerImpl 实现了LayoutInflater.Factory2接口,之前在Activity中我们就看到Activity实现这个接口:

public interface Factory2 extends Factory {
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs);
}

当然,虽然后来在Fragment中添加了这个接口,不过其实里面的实现方式和Activity是一样的。接下来,我们就从使用Fragment开始,查看在我们使用Fragment的时候,到的发生了那些事情。

我们列举一个简单使用Fragment的例子:

FragmentManager fm = getFragmentManager();  
FragmentTransaction ft = fm.beginTransaction();  
ft.add(R.id.id_content, new FragmentImpl());  
ft.commit();

代码中的FragmentImpl表示任意一个Fragment的子类,我们就从这段代码开始,分析Fragment的源码。

首先:

FragmentManager fm = getFragmentManager()

这行代码一般是写在FragmentActivity或者它的子类中的,我们可以在Activity中看到它具体的返回对象:

final FragmentManagerImpl mFragments = new FragmentManagerImpl();
 /**
  *返回一个FragmentManager用来和当前的Activity关联和互动
  */
public FragmentManager getFragmentManager() {
   return mFragments;
}

所以我们可以看到,这个返回的对象就是FragmentManager的实现类FragmentManagerImpl。

接下来:

FragmentTransaction ft = fm.beginTransaction();  

我们看它在FragmentManagerImpl中的实现:

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

返回的是一个BackStackRecord对象,BackStackRecord是FragmentTransaction的子类,实现了FragmentManager.BackStackEntry, Runnable这两个接口,它是用来保存操作动作的一个类。

为什么说它是用来保存操作动作的呢?我们看这行代码:

ft.add(R.id.id_content, new FragmentImpl());  

它就是调用的BackStackRecord中的这个方法:

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;
        //判断fragment的tag,如果传入的tag不为null,那么就将传入的tag赋值给fragment
        //如果原fragment已经有tag的值了,那么就不能更改这个tag的值,否则抛出异常
        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;
        }
        //判断fragment的id,如果传入的id不为0,那么就将传入的id赋值给fragment
        //当然,在赋值之前也会判断fragment的id,如果这个id存在,那么也是不能更改的,否则抛出异常
        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;
        }
        //最后将操作和操作对应的fragment保存到一个Op对象中
        Op op = new Op();
        op.cmd = opcmd;
        op.fragment = fragment;
        addOp(op);
}

我们看到,它最终调用到了BackStackRecord中的这个方法,并且将fragment和cmd保存到了一个Op对象中,而这个cmd正是我们操作的类型。

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;

比如我们刚才调用的是add方法,那么刚才的cmd就是OP_ADD,值为1。

最后:

ft.commit();

实现:

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(Log.VERBOSE, TAG);
        PrintWriter pw = new FastPrintWriter(logw, false, 1024);
        dump("  ", null, pw, null);
        pw.flush();
    }
    mCommitted = true;
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex(this);
    } else {
        mIndex = -1;
    }
    //重要的方法
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}

它最后执行了mManager.enqueueAction(this, allowStateLoss)这行方法

final FragmentManagerImpl mManager;

也就是在讲操作保存到Op对象中后,最后会在FragmentManagerImpl进行执行。
在FragmentManagerImpl的enqueueAction方法中,会先将传入的action,也就是BackStackRecord对象添加到一个mPendingActions的集合中,通过mHandler.post,最后调用到execPendingActions方法。

Runnable mExecCommit = new Runnable() {
        @Override
        public void run() {
            execPendingActions();
        }
    };
ArrayList<Runnable> mPendingActions;
......
mPendingActions.add(action);
mActivity.mHandler.post(mExecCommit);

execPendingActions里就是真正执行保存在Op对象中方法的地方了。

6、execPendingActions方法

在execPendingActions中,首先会判断是否已经执行,是否在主线程执行,如果不满足条件,都会抛出异常。

if (mExecutingActions) {
      throw new IllegalStateException("Recursive entry to executePendingTransactions");
}   
if (Looper.myLooper() != mActivity.mHandler.getLooper()) {
     throw new IllegalStateException("Must be called from main thread of process");
}

然后开始在一个while(true)循环中执行Op对象中保存的命令,直到执行完毕,跳出循环。

while (true) {
    int numActions;
    synchronized (this) {
        //如果保存的Action已经执行完,则跳出循环
        if (mPendingActions == null || mPendingActions.size() == 0) {
            break;
        }
        //获取保存在mPendingActions集合中具体的操作数,并将操作保存到一个临时数组mTmpActions中
        numActions = mPendingActions.size();
        if (mTmpActions == null || mTmpActions.length < numActions) {
            mTmpActions = new Runnable[numActions];
        }
        //清空原集合
        mPendingActions.toArray(mTmpActions);
        mPendingActions.clear();
        mActivity.mHandler.removeCallbacks(mExecCommit);
    }
    //开始循环执行
    mExecutingActions = true;
    for (int i=0; i<numActions; i++) {
        mTmpActions[i].run();
        mTmpActions[i] = null;
    }
    //循环执行结束//开始循环执行
    mExecutingActions = false;
    didSomething = true;
}

在while循环中,会将保存在mPendingActions集合中的对象保存到一个临时数组中,然后循环这个数组,通过调用mTmpActions[i].run()方法执行,然后将执行过的置空mTmpActions[i] = null,直到循环结束。

在BackStackRecord的run方法中,实现了Op对象中各类操作的具体处理,比如刚才使用的add操作,在run方法中的处理:

case OP_ADD: {
    Fragment f = op.fragment;
    f.mNextAnim = op.enterAnim;
    mManager.addFragment(f, false);
}

最后,还是调用到了FragmentManagerImpl中的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(fragment);
        }
    }
}

在addFragment的方法中,首先会调用一个makeActive方法,这个方法将这个Fragment添加到了一个mActive的集合,并且给这个Fragment设置了一个index。然后判断fragment的mDetached是否为false,如果为false才执行下面的操作,否则不执行。

mDetached这个参数是干什么的呢?在我们创建Fragment的时候,这个参数默认是就是false,只有当我们调用
detachFragment这个方法时,才会将这个参数改为true,表示这个fragment已经没有附着在这个activity上。

在判断中,会判断这个fragment是否已经添加过,如果是救抛出异常,否则将它添加到mAdded集合,然后设置一些参数后,调用moveToState方法。

在这个方法中,我们看到了两个方法,一个是makeActive,一个是moveToState。
首先来说makeActive这个方法,它和makeInactive方法是相对的:

void makeActive(Fragment f) {
    if (f.mIndex >= 0) {
        return;
    }
    if (mAvailIndices == null || mAvailIndices.size() <= 0) {
        if (mActive == null) {
            mActive = new ArrayList<Fragment>();
        }
        f.setIndex(mActive.size(), mParent);
        mActive.add(f);
    } else {
        f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1), mParent);
        mActive.set(f.mIndex, f);
    }
    if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
}
void makeInactive(Fragment f) {
    if (f.mIndex < 0) {
        return;
    }
    if (DEBUG) Log.v(TAG, "Freeing fragment index " + f);
    mActive.set(f.mIndex, null);
    if (mAvailIndices == null) {
        mAvailIndices = new ArrayList<Integer>();
    }
    mAvailIndices.add(f.mIndex);
    mActivity.invalidateFragment(f.mWho);
    f.initState();
}

首先:
makeActive方法,判断一个fragment的index,如果这个mIndex大于等于0,那么表示这个fragment已经是active的,直接返回;
makeInactive方法,判断小于0,如果是则直接返回。
然后:
makeActive方法,判断mAvailIndices这个集合是否为空,如果不为空,表示已经存在回收的index,否则创建一个新的index,然后将这个index设置到fragment中,并且以index作为key保存改fragment。
makeInactive方法,将mActivity中key为index的fragment置空,然后将这个key回收到mAvailIndices中,以便后面使用。

看完了这两个方法,然后再看moveToState这个方法。

因为篇幅原因,这篇博客暂时就写到这,下一篇则继续看moveToState这个方法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值