Activity管理Fragment解析
本文出自Lusfold的博客:Activity管理Fragment解析
首先Fragment的生命周期完全由所属的Activity掌控,并没有像Activity一样由AMS管理。
FragmentActivity生命周期与事件分发
先从一张图简单看下各个类之间的关系(这里并没有详细列出所有类以及类的方法,有些不影响分析的类也没有列出):
首先我们来看左边的从Activity到FragmentActivity的继承链条:
1.BaseFragmentActivityDonut:一个抽象类,直接父类就是Activity,其中做了主要做了两件事。其一,从Donut可以看出它做了一些兼容工作,这里不展开。其二,定义了抽象方法dispatchFragmentsOnCreateView,并在重写的onCreateView中调用了它,暂且认为Fragment的实例化就是从这里开始的,事实上它最终会调用fragment.newInstance()。
2.BaseFragmentActivityHoneycomb:Honeycomb,没错,除了做了一些兼容什么都没干。
3.FragmentActivity:它是具有支持Fragment功能的最底层的Activity,后面的AppCompatActivity都是它的子类。
接下来我们来看FragmentActivity、FragmentController、FragmentHostCallBack之间的关系:
1.FragmentActivity:这其中主要负责Activity生命周期与一些常用事件的分发。例如onCreate()、onResume、onDestory等等这些事件,这也就是Fragment生命周期会与Activity同步的原因,再例如onActivityResult、onKeyDown、onBackPressed等事件的分发。那么这些事件通过什么进行分发呢,就是它持有的FragmentController实例。
2.FragmentController:它的介绍如下(简单来说就是负责继续将生命周期分发给它持有的FragmentHostCallback中的FragmentManager):
Provides integration points with a {@link FragmentManager} for a fragment host.
It is the responsibility of the host to take care of the Fragment’s lifecycle.
The methods provided by {@link FragmentController} are for that purpose.
3.HostCallbacks:HostCallBacks是FragmentHostCallback的子类,主要实现了像onAttachFragment、onStartActivityFromFragment、onFindViewById等回调方法,从UML图中可以看出它持有Activity引用,是在如上提到的FragmentActivity创建FragmentController时传入。
4.FragmentHostCallback:如上所说,它持有FragmentActivity的Activity、Context、Handler等引用,为它所持有的FragmentManager提供资源。
5.FragmentManager、FragmentManagerImpl:FragmentManagerImpl是FragmentManager的具体实现类。它可以说是Fragment生命周期管理最重要的类。来看下其中的变量就知道了:
ArrayList<Fragment> mActive;
ArrayList<Fragment> mAdded;
ArrayList<Integer> mAvailIndices;
ArrayList<BackStackRecord> mBackStack;
ArrayList<Fragment> mCreatedMenus;
// Must be accessed while locked.
ArrayList<BackStackRecord> mBackStackIndices;
ArrayList<Integer> mAvailBackStackIndices;
ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
int mCurState = Fragment.INITIALIZING;
FragmentHostCallback mHost;
FragmentController mController;
FragmentContainer mContainer;
Fragment mParent;
再看Fragment状态分发最主要的方法moveToState(由于篇幅原因仅贴出部分,源码可自己查找):
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// Fragments that are not currently added will sit in the onCreate() state.
if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
newState = Fragment.CREATED;
}
if (f.mRemoving && newState > f.mState) {
// While removing a fragment, we can't change it to a higher state.
newState = f.mState;
}
// Defer start if requested; don't allow it to move to STARTED or higher
// if it's not already started.
if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
if (f.mState < newState) {
// For fragments that are created from a layout, when restoring from
// state we don't want to allow them to be created until they are
// being reloaded from the layout.
if (f.mFromLayout && !f.mInLayout) {
return;
}
if (f.mAnimatingAway != null) {
// The fragment is currently being animated... but! Now we
// want to move our state back up. Give up on waiting for the
// animation, move to whatever the final state should be once
// the animation is done, and then we can proceed from there.
f.mAnimatingAway = null;
moveToState(f, f.mStateAfterAnimating, 0, 0, true);
}
switch (f.mState) {
case Fragment.INITIALIZING:
if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
if (f.mSavedFragmentState != null) {
f.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
FragmentManagerImpl.VIEW_STATE_TAG);
f.mTarget = getFragment(f.mSavedFragmentState,
FragmentManagerImpl.TARGET_STATE_TAG);
if (f.mTarget != null) {
f.mTargetRequestCode = f.mSavedFragmentState.getInt(
FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
}
f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
if (!f.mUserVisibleHint) {
f.mDeferStart = true;
if (newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
}
}
f.mHost = mHost;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
f.mCalled = false;
f.onAttach(mHost.getContext());
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onAttach()");
}
if (f.mParentFragment == null) {
mHost.onAttachFragment(f);
}
if (!f.mRetaining) {
f.performCreate(f.mSavedFragmentState);
}
f.mRetaining = false;
if (f.mFromLayout) {
// For fragments that are part of the content view
// layout, we need to instantiate the view immediately
// and the inflater will take care of adding it.
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), null, f.mSavedFragmentState);
if (f.mView != null) {
f.mInnerView = f.mView;
if (Build.VERSION.SDK_INT >= 11) {
ViewCompat.setSaveFromParentEnabled(f.mView, false);
} else {
f.mView = NoSaveStateFrameLayout.wrap(f.mView);
}
if (f.mHidden) f.mView.setVisibility(View.GONE);
f.onViewCreated(f.mView, f.mSavedFragmentState);
} else {
f.mInnerView = null;
}
}
case Fragment.CREATED:
......
至此,FragmentActivity生命周期及事件分发的大致流程已经讲完,接下来说一说FragmentTransaction
FragmentTransaction
先看下与FragmentTransaction相关的几个类:
1.FragmentTransaction:它是抽象类,定义了Transaction相关接口,例如我们经常使用的add()、replace()、remove()、attach、commit()等方法。
2.BackStackRecord:它是FragmentTransaction的具体实现类,并实现了Runnable接口(这相当关键)。相关代码:
static final class Op {
Op next;
Op prev;
int cmd;
Fragment fragment;
int enterAnim;
int exitAnim;
int popEnterAnim;
int popExitAnim;
ArrayList<Fragment> removed;
}
Op mHead;
Op mTail;
非常直白,利用双向链表存储所有操作。没错!FragmentTransaction定义的各种接口实现就是各种类型Op的添加。然后来看下它是如何Commit的:
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);
}
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
这个allowStateLoss参数就是那个commitAllowingStateLoss方法确定的(不深入介绍)。
最关键的一句: mManager.enqueueAction(this, allowStateLoss);,继续追踪:
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>();
}
mPendingActions.add(action);
if (mPendingActions.size() == 1) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}
最终通过使用HostCallback持有的FragmentActivity的Handler向主线程发送消息,让主线程反过来调用FragmentManager的execPendingActions()方法,从而使BackStackRecord的run()(还记得BackStackRecord实现了Runnable接口么)在主线程执行。那么BackStackRecord的run()方法这里就不贴出来了,具体内容总结就是根据不同的操作调用FragmentManager的各种转换Fragment生命周期的方法。
其它
1.Fragment中onHiddenChanged()与setUserVisibleHint()方法的区别:onHiddenChanged是在我们进行Transaction是进行show或hide操作时的回调,setUserVisibleHint是设置一个标志来确定此Fragment是否对用户可见,原文是:
An app may set this to false to indicate that the fragment’s UI is scrolled out of visibility or is otherwise not directly visible to the user.This may be used by the system to prioritize operations such as fragment lifecycle updates
or loader ordering behavior.
例如FragmentAdapter在Fragment滑入滑出时会调用此方法,可重写此方法进行懒加载。