${XXX}
为何会有这么多get${XXX}FragmentManager
,它们存在目的是什么呢
FragmentActivity
- getSupportFragmentManager
- getFragmentManager
Fragment
- getFragmentManager
- getChildFragmentManager
FragmentActivity.getSupportFragmentManager()
代码取自 v4兼容包
/**
* Return the FragmentManager for interacting with fragments associated
* with this activity.
*/
public FragmentManager getSupportFragmentManager() {
return mFragments.getSupportFragmentManager();
}
跟进mFragments
看到
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
继续跟进FragmentController
,FragmentController
的方法列表如下:
/** Attaches the host to the FragmentManager for this controller. The host must be attached before the FragmentManager can be used to manage Fragments.*/
attachHost
createController
/**dispatch fragment lifecycle */
onCreateView
dispatchActivityCreated
dispatchConfigurationChanged
dispatchContextItemSelected
dispatchCreate
dispatchCreateOptionsMenu
dispatchDestroy
dispatchDestroyView
dispatchLowMemory
dispatchOptionsItemSelected
dispatchOptionsMenuClosed
dispatchPause
dispatchPrepareOptionsMenu
dispatchReallyStop
dispatchResume
dispatchStart
dispatchStop
/**dispatch loader*/
doLoaderDestroy
doLoaderRetain
doLoaderStart
doLoaderStop
dumpLoaders
reportLoaderStart
restoreLoaderNonConfig
retainLoaderNonConfig
/**Execute any pending actions for the Fragments managed by the controller's FragmentManager.
Call when queued actions can be performed [eg when the Fragment moves into a start or resume state].*/
execPendingActions
getActiveFragments
getActiveFragmentsCount
/**Returns a {@link FragmentManager} for this controller.*/
getSupportFragmentManager
/**Returns a {@link LoaderManager}.*/
getSupportLoaderManager
/**Bundle state manager*/
noteStateNotSaved
restoreAllState
retainNonConfig
saveAllState
/**
Provides integration points with a FragmentManager for a fragment host.
It is the responsibility of the host to take care of the Fragment's lifecycle. The methods provided by FragmentController are for that purpose.
*/
class FragmentController{
private final FragmentHostCallback<?> mHost;
// ignore ...
}
查看源代码之后,FragmentController
做了如下几件事情:
- 提供单例方法
createController
用于创建实例; - 提供
attachHost(Fragment parent)
,通过FragmentController
将Host
,Fragment
,FragmentContainer
附加到FragmentManager
; - 提供分发
Fragment
的生命周期的方法; - 提供存储/恢复
SaveState
的方法,用于处理Fragment
的状态恢复; - 提供分发
LoaderMananger
的回调方法;
接着跟进FragmentHostCallback
,查看继承关系如下:
/**
Integration points with the Fragment host.Fragments may be hosted by any object; such as an Activity.
In order to host fragments, implement FragmentHostCallback, overriding the methods applicable to the host.*/
--Object (java.lang)
----FragmentContainer (android.support.v4.app)
------FragmentHostCallback (android.support.v4.app)
--------HostCallbacks in FragmentActivity (android.support.v4.app)
FragmentHostCallback存在的意义,上面的注释中已经说明的很明白了,那么继续跟进它在FragmentActivity
中的 usage。
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
OK,FragmentController
已经清晰的展示它的职责。
那么继续回到代码:
public FragmentManager getSupportFragmentManager() {
return mFragments.getSupportFragmentManager();
}
跟进FragmentHostCallback
:
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
FragmentManagerImpl getFragmentManagerImpl() {
return mFragmentManager;
}
继续跟进FragmentManagerImpl
,
Object (java.lang)
--FragmentManager (android.support.v4.app)
----FragmentManagerImpl (android.support.v4.app)
愈来愈接近FragmentManager
( 对 FragmentManager 不了解?点我!)。我们了解到FragmentManager
只是一个抽象类,实际的实现类只有FragmentManagerImpl
一个而已。
先不慌忙,先啃掉FragmentManagerImpl
再回头看看为什么。
// Read The Fuck Code!(RTFC)
// 已忽略掉无关的代码
final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory {
/** 一个pending 列表,借助 handler 将 Runnable 转发到execPendingActions()中。在execPendingActions()经由中转 Runnable 执行任务。*/
ArrayList<Runnable> mPendingActions;
/**{@link #moveToState()}*/
int mCurState = Fragment.INITIALIZING;
/**{@link FragmentController#attachController()}*/
FragmentHostCallback mHost;
FragmentController mController;
FragmentContainer mContainer;
Fragment mParent;
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
}
@Override
public boolean executePendingTransactions() {
return execPendingActions();
}
@Override
public FragmentTransaction beginTransaction() {
// BackStackRecord 简要说就是记录“你从哪里来,到哪里去。”
// 如:你从 A 处来,要去往 B处。
// 记录的是:这个事务(从 A 来,要去 B。),而不是目的{A,B}。
// 具体,可以跟进{@link BackStackRecord}
return new BackStackRecord(this);
}
@Override
public void popBackStack() {
enqueueAction(new Runnable() {
@Override public void run() {
popBackStackState(mHost.getHandler(), null, -1, 0);
}
}, false);
}
@Override
public boolean popBackStackImmediate() {
checkStateLoss();
executePendingTransactions();
return popBackStackState(mHost.getHandler(), null, -1, 0);
}
@Override
public int getBackStackEntryCount() {
return mBackStack != null ? mBackStack.size() : 0;
}
/**
*增加了一个action,等待队列的操作。
* @param action 待添加的行为
* @param allowStateLoss 是否允许丢失状态
* @throws IllegalStateException if the activity has been destroyed
*/
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);
}
}
}
public boolean execPendingActions() {
//...
while (true) {
int numActions;
synchronized (this) {
if (mPendingActions == null || mPendingActions.size() == 0) {
break;
}
numActions = mPendingActions.size();
if (mTmpActions == null || mTmpActions.length < numActions) {
mTmpActions = new Runnable[numActions];
}
mPendingActions.toArray(mTmpActions);
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
}
mExecutingActions = true;
for (int i=0; i<numActions; i++) {
mTmpActions[i].run();
mTmpActions[i] = null;
}
mExecutingActions = false;
didSomething = true;
}
//...
}
/** 对 Fragment 的状态分发的管理的实现,调用可参考{@link FragmentController#dispatch${XXX}};这个方法所做的事情是,根据状态等一系列参数,让fragment 做出对应的实现。*/
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// 有兴趣的可行阅读代码
}
}
先总结下FragmentManagerImpl
做了哪些事情?
1.BackStackRecord
管理,派生于(FragmentTransaction
),然最终是对 BackStackRecord.Op
的管理。
2.Fragment
状态的管理。
Fragment.getFragmentManager()
public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener {
// The fragment manager we are associated with. Set as soon as the
// fragment is used in a transaction; cleared after it has been removed
// from all transactions.
FragmentManagerImpl mFragmentManager;
// Private fragment manager for child fragments inside of this one.
FragmentManagerImpl mChildFragmentManager;
final public FragmentManager getFragmentManager() {
return mFragmentManager;
}
/**
* Return a private FragmentManager for placing and managing Fragments
* inside of this Fragment.
*/
final public FragmentManager getChildFragmentManager() {
if (mChildFragmentManager == null) {
instantiateChildFragmentManager();
if (mState >= RESUMED) {
mChildFragmentManager.dispatchResume();
} else if (mState >= STARTED) {
mChildFragmentManager.dispatchStart();
} else if (mState >= ACTIVITY_CREATED) {
mChildFragmentManager.dispatchActivityCreated();
} else if (mState >= CREATED) {
mChildFragmentManager.dispatchCreate();
}
}
return mChildFragmentManager;
}
}
最终都是引用FragmentManagerImpl
,证明他们并无分别。所以调用enableDebugLogging
方法,无论调用 get${XXX}FragmentManager均会打印日志。
public abstract class FragmentManager {
/**
* Control whether the framework's internal fragment manager debugging
* logs are turned on. If enabled, you will see output in logcat as
* the framework performs fragment operations.
*/
public static void enableDebugLogging(boolean enabled) {
FragmentManagerImpl.DEBUG = enabled;
}
}
而getChildFragmentManager
与getFragmentManager
的区别有二。
- 不同的 instance;
- 增加对其持有的 fragment 的lifecycle 的更新;
附上日志:
描述了:从 ViewPager内部的 Fragment点击跳转到新的 Fragment,并点击返回的过程。
Tip:
–ViewPager使用getChildFragmentManager
,如果换成getFragmentManager
。那么 点击返回的时候 viewPager 所持有的 Fragment 是得不到生命周期调用的,所以往往点击返回 后是显示空白的页面。注意日志中ViewPagerChildFragment
的movefrom
部分。
FragmentManager: Commit: BackStackEntry{28cbf0d0}
******FragmentManager: mName=null mIndex=-1 mCommitted=false
******FragmentManager: Operations:
******FragmentManager: Op #0: REPLACE DetailFragment{28cbf278 id=0x7f0c0050}
FragmentManager: Setting back stack index 1 to BackStackEntry{28cbf0d0}
FragmentManager: Run: BackStackEntry{28cbf0d0 #1}
FragmentManager: Bump nesting in BackStackEntry{28cbf0d0 #1} by 1
FragmentManager: Bump nesting of DetailFragment{28cbf278 id=0x7f0c0050} to 1
FragmentManager: OP_REPLACE: adding=DetailFragment{28cbf278 id=0x7f0c0050} old=DispatchFragment{28c8e800 #0 id=0x7f0c0050}
FragmentManager: Bump nesting of DispatchFragment{28c8e800 #0 id=0x7f0c0050} to 2
FragmentManager: remove: DispatchFragment{28c8e800 #0 id=0x7f0c0050} nesting=2
FragmentManager: movefrom RESUMED: DispatchFragment{28c8e800 #0 id=0x7f0c0050}
FragmentManager: movefrom RESUMED: ViewPagerChildFragment{28cb1038 #0 id=0x7f0c0051}
FragmentManager: movefrom RESUMED: ViewPagerChildFragment{28cb1120 #1 id=0x7f0c0051}
FragmentManager: movefrom STARTED: DispatchFragment{28c8e800 #0 id=0x7f0c0050}
FragmentManager: movefrom STARTED: ViewPagerChildFragment{28cb1038 #0 id=0x7f0c0051}
FragmentManager: movefrom STARTED: ViewPagerChildFragment{28cb1120 #1 id=0x7f0c0051}
FragmentManager: movefrom STOPPED: DispatchFragment{28c8e800 #0 id=0x7f0c0050}
FragmentManager: movefrom STOPPED: ViewPagerChildFragment{28cb1038 #0 id=0x7f0c0051}
FragmentManager: movefrom STOPPED: ViewPagerChildFragment{28cb1120 #1 id=0x7f0c0051}
FragmentManager: movefrom ACTIVITY_CREATED: DispatchFragment{28c8e800 #0 id=0x7f0c0050}
FragmentManager: movefrom ACTIVITY_CREATED: ViewPagerChildFragment{28cb1038 #0 id=0x7f0c0051}
FragmentManager: movefrom ACTIVITY_CREATED: ViewPagerChildFragment{28cb1120 #1 id=0x7f0c0051}
FragmentManager: add: DetailFragment{28cbf278 id=0x7f0c0050}
FragmentManager: Allocated fragment index DetailFragment{28cbf278 #1 id=0x7f0c0050}
FragmentManager: moveto CREATED: DetailFragment{28cbf278 #1 id=0x7f0c0050}
FragmentManager: moveto ACTIVITY_CREATED: DetailFragment{28cbf278 #1 id=0x7f0c0050}
FragmentManager: moveto STARTED: DetailFragment{28cbf278 #1 id=0x7f0c0050}
FragmentManager: moveto RESUMED: DetailFragment{28cbf278 #1 id=0x7f0c0050}
FragmentManager: popFromBackStack: BackStackEntry{28cbf0d0 #1}
******FragmentManager: mName=null mIndex=1 mCommitted=true
******FragmentManager: Operations:
******FragmentManager: Op #0: REPLACE DetailFragment{28cbf278 #1 id=0x7f0c0050}
******FragmentManager: Removed: DispatchFragment{28c8e800 #0 id=0x7f0c0050}
FragmentManager: Bump nesting in BackStackEntry{28cbf0d0 #1} by -1
FragmentManager: Bump nesting of DetailFragment{28cbf278 #1 id=0x7f0c0050} to 0
FragmentManager: Bump nesting of DispatchFragment{28c8e800 #0 id=0x7f0c0050} to 1
FragmentManager: remove: DetailFragment{28cbf278 #1 id=0x7f0c0050} nesting=0
FragmentManager: movefrom RESUMED: DetailFragment{28cbf278 #1 id=0x7f0c0050}
FragmentManager: movefrom STARTED: DetailFragment{28cbf278 #1 id=0x7f0c0050}
FragmentManager: movefrom STOPPED: DetailFragment{28cbf278 #1 id=0x7f0c0050}
FragmentManager: movefrom ACTIVITY_CREATED: DetailFragment{28cbf278 #1 id=0x7f0c0050}
FragmentManager: movefrom CREATED: DetailFragment{28cbf278 #1 id=0x7f0c0050}
FragmentManager: Freeing fragment index DetailFragment{28cbf278 #1 id=0x7f0c0050}
FragmentManager: add: DispatchFragment{28c8e800 #0 id=0x7f0c0050}
FragmentManager: moveto ACTIVITY_CREATED: DispatchFragment{28c8e800 #0 id=0x7f0c0050}
FragmentManager: moveto ACTIVITY_CREATED: ViewPagerChildFragment{28cb1038 #0 id=0x7f0c0051}
FragmentManager: moveto ACTIVITY_CREATED: ViewPagerChildFragment{28cb1120 #1 id=0x7f0c0051}
FragmentManager: moveto STARTED: DispatchFragment{28c8e800 #0 id=0x7f0c0050}
FragmentManager: moveto STARTED: ViewPagerChildFragment{28cb1038 #0 id=0x7f0c0051}
FragmentManager: moveto STARTED: ViewPagerChildFragment{28cb1120 #1 id=0x7f0c0051}
FragmentManager: moveto RESUMED: DispatchFragment{28c8e800 #0 id=0x7f0c0050}
FragmentManager: moveto RESUMED: ViewPagerChildFragment{28cb1038 #0 id=0x7f0c0051}
FragmentManager: moveto RESUMED: ViewPagerChildFragment{28cb1120 #1 id=0x7f0c0051}
FragmentManager: Freeing back stack index 1