概述 Fragment
表示 Activity 中的行为或用户界面部分。您可以将多个 Fragment 组合在一个 Activity 中来构建多窗格 UI,以及在多个 Activity 中重复使用某个 Fragment。您可以将 Fragment 视为 Activity 的模块化组成部分,它具有自己的生命周期,能接收自己的输入事件,并且您可以在 Activity 运行时添加或移除 Fragment。 Fragment 必须始终嵌入在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影响。 例如,当 Activity 暂停时,其中的所有 Fragment 也会暂停;当 Activity 被销毁时,所有 Fragment 也会被销毁。 不过,当 Activity 正在运行(处于已恢复生命周期状态)时,您可以独立操纵每个 Fragment,如添加或移除它们。 当您执行此类 Fragment 事务时,您也可以将其添加到由 Activity 管理的返回栈 — Activity 中的每个返回栈条目都是一条已发生 Fragment 事务的记录。 返回栈让用户可以通过按返回按钮撤消 Fragment 事务(后退)。
当您将 Fragment 作为 Activity 布局的一部分添加时,它存在于 Activity 视图层次结构的某个 ViewGroup 内部,并且 Fragment 会定义其自己的视图布局。您可以通过在 Activity 的布局文件中声明Fragment,将其作为 <fragment>
元素插入您的 Activity 布局中,或者通过将其添加到某个现有 ViewGroup,利用应用代码进行插入。不过,Fragment 并非必须成为 Activity 布局的一部分;您还可以将没有自己 UI 的 Fragment 用作 Activity 的不可见工作线程。
本文将通过分析源码,对 Fragment 的创建、销毁以及生命周期做一个更深入的认识。
建议读者在看这篇文章的时候,先看下Fragment事务管理源码分析 ,对Fragment管理类先有一个比较清楚的认识。
分析入口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 protected void showFragment (@IdRes int containerViewId, Class<? extends Fragment> clz) { FragmentManager fm = getFragmentManager(); FragmentTransaction ft = fm.beginTransaction(); try { Fragment f = clz.newInstance(); ft.add(containerViewId, f, clz.getName()); ft.commit(); } catch (Exception e) { e.printStackTrace(); } }
上面的代码就是动态地往containerViewId
里添加一个Fragment并让它显示出来,可以看到,这个涉及到Fragment的事务管理,详细可以参考Fragment事务管理源码分析 ,这里就不再阐述了。
代码分析 BackStackRecord#run 调用了commit之后,真正执行的地方是在BackStackRecord的run方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 public void run () { ...... if (mManager.mCurState >= Fragment.CREATED) { SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>(); SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>(); calculateFragments(firstOutFragments, lastInFragments); beginTransition(firstOutFragments, lastInFragments, false ); } 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 ; case OP_REPLACE: { Fragment f = op.fragment; int containerId = f.mContainerId; if (mManager.mAdded != null ) { for (int i = mManager.mAdded.size() - 1 ; i >= 0 ; i--) { Fragment old = mManager.mAdded.get(i); if (old.mContainerId == containerId) { if (old == f) { op.fragment = f = null ; } else { if (op.removed == null ) { op.removed = new ArrayList<Fragment>(); } op.removed.add(old); old.mNextAnim = op.exitAnim; if (mAddToBackStack) { old.mBackStackNesting += 1 ; } mManager.removeFragment(old, mTransition, mTransitionStyle); } } } } if (f != null ) { f.mNextAnim = op.enterAnim; mManager.addFragment(f, false ); } } break ; case OP_REMOVE: { Fragment f = op.fragment; f.mNextAnim = op.exitAnim; mManager.removeFragment(f, mTransition, mTransitionStyle); } break ; case OP_HIDE: { Fragment f = op.fragment; f.mNextAnim = op.exitAnim; mManager.hideFragment(f, mTransition, mTransitionStyle); } break ; case OP_SHOW: { Fragment f = op.fragment; f.mNextAnim = op.enterAnim; mManager.showFragment(f, mTransition, mTransitionStyle); } break ; case OP_DETACH: { Fragment f = op.fragment; f.mNextAnim = op.exitAnim; mManager.detachFragment(f, mTransition, mTransitionStyle); } break ; case OP_ATTACH: { Fragment f = op.fragment; f.mNextAnim = op.enterAnim; mManager.attachFragment(f, mTransition, mTransitionStyle); } break ; default : { throw new IllegalArgumentException("Unknown cmd: " + op.cmd); } } op = op.next; } mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true ); if (mAddToBackStack) { mManager.addBackStackState(this ); } }
因为我们调用的是add操作,所以执行的代码片段是:
1 2 3 4 5 6 case OP_ADD: { Fragment f = op.fragment; f.mNextAnim = op.enterAnim; mManager.addFragment(f, false ); } break ;
参数解释:
op.fragment:showFragment中创建的Fragment实例,并且现在Fragment的mTag、mFragmentId、mContainerId已被初始化过了
op.enterAnim:入场动画,可以先不管
mManager:FragmentManagerImpl实例
FragmentManagerImpl#addFragment 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public void addFragment (Fragment fragment, boolean moveToStateNow) { if (mAdded == null ) { mAdded = new ArrayList<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里面把Fragment加入mActive和mAdded列表,并且设置标记为fragment.mAdded
为true,fragment.mRemoving
为false。 执行完ADD操作后,执行moveToState,moveToState顾名思义,就是把Fragment变为某种状态
1 2 3 4 5 6 7 8 mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true ); if (mAddToBackStack) { mManager.addBackStackState(this ); }
Fragment状态 我们知道Fragment的生命周期是依赖于Activity的,比如Activity处于onResume,那么Fragment也会处于onResume状态,这里的参数mManager.mCurState对应的状态有:
1 2 3 4 5 6 7 static final int INVALID_STATE = -1 ; static final int INITIALIZING = 0 ; static final int CREATED = 1 ; static final int ACTIVITY_CREATED = 2 ; static final int STOPPED = 3 ; static final int STARTED = 4 ; static final int RESUMED = 5 ;
mCurState的初始状态是Fragment.INITIALIZING,那么在BackStackRecord中调用moveToState的时候,mCurState是什么值呢?它是会受Activity生命周期影响而变化的,我们来看下FragmentActivity
的代码
1 2 3 4 5 6 7 8 9 10 11 12 @SuppressWarnings ("deprecation" )@Override protected void onCreate (@Nullable Bundle savedInstanceState) { mFragments.attachHost(null ); super .onCreate(savedInstanceState); ... ... mFragments.dispatchCreate(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public void dispatchCreate () { mHost.mFragmentManager.dispatchCreate(); } public void dispatchCreate () { mStateSaved = false ; moveToState(Fragment.CREATED, false ); } void moveToState (int newState, boolean always) { moveToState(newState, 0 , 0 , always); } void moveToState (int newState, int transit, int transitStyle, boolean always) { ... ... mCurState = newState; ... ... }
在onCreate中把mCurState变为Fragment.CREATED
状态了,Activity的其他生命周期方法回调的时候,也会改变这个状态,大致整理如下:
onCreate:Fragment.CREATED
onStart:Fragment.ACTIVITY_CREATED–>Fragment.STARTED (Fragment.ACTIVITY_CREATED只会在Activity创建之后触发一次,Fragment.STARTED每次onStart的时候都会触发)
onResume:Fragment.RESUMED
onPause:Fragment.STARTED
onStop:Fragment.STOPPED
onDestroy:Fragment.INITIALIZING
下面是一张状态迁移图:
所以随着Activity生命周期的推进,Activity内所有Fragment的生命周期也会跟着推进。从Activity创建到显示出来,最后会处于onResume状态,那么我们这次就直接分析当前Activity处于onResume调用之后的情形好了。所以假定现在mCurState为Fragment.RESUMED ,
让我们继续跟踪FragmentManagerImpl
FragmentManagerImpl#moveToState 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 void moveToState (int newState, int transit, int transitStyle, boolean always) { if (mHost == null && newState != Fragment.INITIALIZING) { throw new IllegalStateException("No activity" ); } if (!always && mCurState == newState) { return ; } mCurState = newState; if (mActive != null ) { boolean loadersRunning = false ; for (int i=0 ; i<mActive.size(); i++) { Fragment f = mActive.get(i); if (f != null ) { moveToState(f, newState, transit, transitStyle, false ); if (f.mLoaderManager != null ) { loadersRunning |= f.mLoaderManager.hasRunningLoaders(); } } } if (!loadersRunning) { startPendingDeferredFragments(); } if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) { mHost.onInvalidateOptionsMenu(); mNeedMenuInvalidate = false ; } } }
设置最新的mCurState状态,通过上面的分析,我们知道newState等于Fragment.RESUMED。遍历mActive列表中保存的Fragment,改变Fragment状态,这里又调用了一个moveToState
方法,这个方法就是真正回调Fragment生命周期的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 void moveToState (Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) { if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) { newState = Fragment.CREATED; } if (f.mRemoving && newState > f.mState) { newState = f.mState; } if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) { newState = Fragment.STOPPED; } if (f.mState < newState) { ...... switch (f.mState) { case Fragment.INITIALIZING: if (f.mSavedFragmentState != null ) { ...... } 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); } else { f.mParentFragment.onAttachFragment(f); } if (!f.mRetaining) { f.performCreate(f.mSavedFragmentState); } else { f.restoreChildFragmentState(f.mSavedFragmentState, true ); f.mState = Fragment.CREATED; } f.mRetaining = false ; if (f.mFromLayout) { f.mView = f.performCreateView(f.getLayoutInflater( f.mSavedFragmentState), null , f.mSavedFragmentState); if (f.mView != null ) { f.mView.setSaveFromParentEnabled(false ); if (f.mHidden) f.mView.setVisibility(View.GONE); f.onViewCreated(f.mView, f.mSavedFragmentState); } } case Fragment.CREATED: if (newState > Fragment.CREATED) { if (!f.mFromLayout) { ViewGroup container = null ; if (f.mContainerId != 0 ) { if (f.mContainerId == View.NO_ID) { throwException(new IllegalArgumentException("" )); } container = (ViewGroup) mContainer.onFindViewById(f.mContainerId); if (container == null && !f.mRestored) { ...... } } f.mContainer = container; f.mView = f.performCreateView(f.getLayoutInflater( f.mSavedFragmentState), container, f.mSavedFragmentState); if (f.mView != null ) { f.mView.setSaveFromParentEnabled(false ); if (container != null ) { Animator anim = loadAnimator(f, transit, true , transitionStyle); if (anim != null ) { anim.setTarget(f.mView); setHWLayerAnimListenerIfAlpha(f.mView, anim); anim.start(); } container.addView(f.mView); } if (f.mHidden) f.mView.setVisibility(View.GONE); f.onViewCreated(f.mView, f.mSavedFragmentState); } } f.performActivityCreated(f.mSavedFragmentState); if (f.mView != null ) { f.restoreViewState(f.mSavedFragmentState); } f.mSavedFragmentState = null ; } case Fragment.ACTIVITY_CREATED: if (newState > Fragment.ACTIVITY_CREATED) { f.mState = Fragment.STOPPED; } case Fragment.STOPPED: if (newState > Fragment.STOPPED) { if (DEBUG) Log.v(TAG, "moveto STARTED: " + f); f.performStart(); } case Fragment.STARTED: if (newState > Fragment.STARTED) { f.performResume(); f.mSavedFragmentState = null ; f.mSavedViewState = null ; } } } else if (f.mState > newState) { ...... } if (f.mState != newState) { f.mState = newState; } }
这段代码逻辑还是比较长,我把注释写在代码里了。可以看到,这个代码写得很巧妙,通过switch case控制,可以一层一层地把Fragment的生命周期推进下去,比如当前fragnemt的state是Fragment.STARTED
,那么它就只会执行performResume,如果Fragment的状态是Fragment.INITIALIZING
,那么就会从switch的最开始依次执行下来,把Fragment的生命周期onAttach–>onResume依次调用。 简要说明下上面的代码:
mHost是FragmentHostCallback抽象类的实例,它的实现类是Activity的HostCallbacks
mParent为null
mHost.getContext()获取的context就是宿主Activity实例
Fragment中创建的View会自动通过container.addView(f.mView)添加到父控件中
很多Fragment的生命周期是通过Fragment的performXxx()方法去调用的,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 void performCreate (Bundle savedInstanceState) { ...... onCreate(savedInstanceState); ...... } View performCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ...... return onCreateView(inflater, container, savedInstanceState); } void performActivityCreated (Bundle savedInstanceState) { ...... onActivityCreated(savedInstanceState); ...... } void performStart () { ...... onStart(); ...... } void performResume () { ...... onResume(); ...... }
Fragment状态的降级操作 有些童鞋们可能会有疑问,上面只分析到了onAttach->onResume生命周期的回调,那onPause、onDestroy等方法又是什么时候执行的呢?我们再看下刚才的代码
1 2 3 4 5 6 if (f.mState < newState) { ...... } else if (f.mState > newState) { ...... }
答案就是在else if分支里面,比如当Acivity锁屏的时候,就Activity生命周期会自动回调onPause,从而触发dispatchPause,在里面调用moveToState(Fragment.STARTED, false); 由于Fragment当前的状态是RESUMED状态,大于newState,所以就会走else if的分支,触发相应的生命周期方法。else if分支的逻辑和state升级的差不多,这里就再进行分析了
生命周期 最后,放张官网上公布的Fragment生命周期图,通过代码分析,我们发现代码的中生命周期的调用顺序和图中确实是一致的
总结 本文大致地从源码的角度分析了Fragment创建、生命周期回调的过程,如果读者对Fragment的remove
、replace
、hide
、detach
、attach
等操作有兴趣的话,可以自行分析,核心代码主要在BackStackRecord类的run方法以及FragmentManagerImpl的moveToState方法中。