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 事務(後退)。java
當您將 Fragment 做爲 Activity 佈局的一部分添加時,它存在於 Activity 視圖層次結構的某個 ViewGroup 內部,而且 Fragment 會定義其本身的視圖佈局。您能夠經過在 Activity 的佈局文件中聲明Fragment,將其做爲 <fragment>
元素插入您的 Activity 佈局中,或者經過將其添加到某個現有 ViewGroup,利用應用代碼進行插入。不過,Fragment 並不是必須成爲 Activity 佈局的一部分;您還能夠將沒有本身 UI 的 Fragment 用做 Activity 的不可見工做線程。ide
本文將經過分析源碼,對 Fragment 的建立、銷燬以及生命週期作一個更深刻的認識。模塊化
建議讀者在看這篇文章的時候,先看下Fragment事務管理源碼分析,對Fragment管理類先有一個比較清楚的認識。源碼分析
/** * 構造並顯示Fragment * * @param containerViewId 容器控件id * @param clz Fragment類 */
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事務管理源碼分析,這裏就再也不闡述了。佈局
調用了commit以後,真正執行的地方是在BackStackRecord的run方法:動畫
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);
}
//遍歷鏈表,根據cmd事務類型依次處理事務
Op op = mHead;
while (op != null) {
switch (op.cmd) {
case OP_ADD: {
//添加一個新的Fragment
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操做,因此執行的代碼片斷是:this
case OP_ADD: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
}
break;
複製代碼
參數解釋:spa
public void addFragment(Fragment fragment, boolean moveToStateNow) {
//已添加的Fragment列表
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}
//設置Fragment的mIndex,並把Fragment添加到mActive列表
makeActive(fragment);
//判斷是否被detach。默認爲false
if (!fragment.mDetached) {
if (mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment already added: " + fragment);
}
//把Fragment添加到mAdded列表
mAdded.add(fragment);
//設置Fragment標記位
fragment.mAdded = true;
fragment.mRemoving = false;
//判斷是否須要刷新菜單
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
//在此次分析中moveToStateNow爲false,moveToState方法在本方法外層方法中調用
if (moveToStateNow) {
moveToState(fragment);
}
}
}
複製代碼
addFragment裏面把Fragment加入mActive和mAdded列表,而且設置標記爲fragment.mAdded
爲true,fragment.mRemoving
爲false。 執行完ADD操做後,執行moveToState,moveToState顧名思義,就是把Fragment變爲某種狀態.net
//mManager.mCurState的狀態很重要,咱們下面會分析它如今處於什麼狀態
mManager.moveToState(mManager.mCurState, mTransition,
mTransitionStyle, true);
//添加本次操做到回退棧中
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
複製代碼
咱們知道Fragment的生命週期是依賴於Activity的,好比Activity處於onResume,那麼Fragment也會處於onResume狀態,這裏的參數mManager.mCurState對應的狀態有:線程
static final int INVALID_STATE = -1; // Invalid state used as a null value.
static final int INITIALIZING = 0; // Not yet created.
static final int CREATED = 1; // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
static final int STOPPED = 3; // Fully created, not started.
static final int STARTED = 4; // Created and started, not resumed.
static final int RESUMED = 5; // Created started and resumed.
複製代碼
mCurState的初始狀態是Fragment.INITIALIZING,那麼在BackStackRecord中調用moveToState的時候,mCurState是什麼值呢?它是會受Activity生命週期影響而變化的,咱們來看下FragmentActivity
的代碼
@SuppressWarnings("deprecation")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
//綁定FragmentManager
mFragments.attachHost(null /*parent*/);
super.onCreate(savedInstanceState);
... ...
//分發Fragment的create事件
mFragments.dispatchCreate();
}
複製代碼
public void dispatchCreate() {
mHost.mFragmentManager.dispatchCreate();
}
public void dispatchCreate() {
mStateSaved = false;
//注意這裏設置了新的state
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賦值
mCurState = newState;
... ...
}
複製代碼
在onCreate中把mCurState變爲Fragment.CREATED
狀態了,Activity的其餘生命週期方法回調的時候,也會改變這個狀態,大體整理以下:
下面是一張狀態遷移圖:
因此隨着Activity生命週期的推動,Activity內全部Fragment的生命週期也會跟着推動。從Activity建立到顯示出來,最後會處於onResume狀態,那麼咱們此次就直接分析當前Activity處於onResume調用以後的情形好了。因此假定如今mCurState爲Fragment.RESUMED,
讓咱們繼續跟蹤FragmentManagerImpl
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;
//遍歷全部Active狀態的Fragment,改變全部Fragment的狀態
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();
}
//讓Activity刷新Menu
if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
mHost.onInvalidateOptionsMenu();
mNeedMenuInvalidate = false;
}
}
}
複製代碼
設置最新的mCurState狀態,經過上面的分析,咱們知道newState等於Fragment.RESUMED。遍歷mActive列表中保存的Fragment,改變Fragment狀態,這裏又調用了一個moveToState
方法,這個方法就是真正回調Fragment生命週期的地方
void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) {
// Fragments被detach或Fragment沒有添加到mAdded列表的話,設置目標Fragment的新狀態爲CREATED狀態,這次分析中不會進入這個分支
if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
newState = Fragment.CREATED;
}
//這次分析中f.mRemoving爲false
if (f.mRemoving && newState > f.mState) {
// While removing a fragment, we can't change it to a higher state.
newState = f.mState;
}
// 是否延時啓動
if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
if (f.mState < newState) {
//這次命中的分支
......
//根據Fragment當前的狀態,選擇case的分支。須要注意的是,這裏的switch case是沒有break語句的。這種設計可讓Fragment把自身的狀態依次推動到目標狀態
switch (f.mState) {
case Fragment.INITIALIZING:
if (f.mSavedFragmentState != null) {
......
}
f.mHost = mHost;
//mParent是在FragmentActivity的onCreate方法中調用attachHost傳進來的,傳進來的是空值
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
f.mCalled = false;
//【Fragment生命週期】onAttach回調,裏面會把mCalled設置爲true
f.onAttach(mHost.getContext());
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onAttach()");
}
if (f.mParentFragment == null) {
//讓Activity能夠監聽到Fragment的attach
mHost.onAttachFragment(f);
} else {
f.mParentFragment.onAttachFragment(f);
}
//f.mRetaining默認爲false
if (!f.mRetaining) {
//關鍵代碼,內部會調用【Fragment生命週期】onCreate
f.performCreate(f.mSavedFragmentState);
} else {
f.restoreChildFragmentState(f.mSavedFragmentState, true);
f.mState = Fragment.CREATED;
}
f.mRetaining = false;
//Fragment是否認義在Layout文件的<fragment>標籤中的,本次栗子爲代碼動態添加Fragment,因此爲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.mView.setSaveFromParentEnabled(false);
if (f.mHidden) f.mView.setVisibility(View.GONE);
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
//注意,這裏沒有break
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
if (!f.mFromLayout) {
//開始建立Fragment的view
ViewGroup container = null;
if (f.mContainerId != 0) {
if (f.mContainerId == View.NO_ID) {
throwException(new IllegalArgumentException(""));
}
//調用Activity的findViewById方法查找控件
container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
......
}
}
f.mContainer = container;
//關鍵代碼,內部會調用【Fragment生命週期】onCreateView,並返回Fragment中new出的視圖
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();
}
//把Fragment的view加入到父控件
container.addView(f.mView);
}
if (f.mHidden) f.mView.setVisibility(View.GONE);
//【Fragment生命週期】onViewCreated回調
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
//關鍵代碼,內部會調用【Fragment生命週期】onActivityCreated
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);
//關鍵代碼,內部會調用【Fragment生命週期】onStart
f.performStart();
}
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
//關鍵代碼,內部會調用【Fragment生命週期】onResume
f.performResume();
// Get rid of this in case we saved it and never needed it.
f.mSavedFragmentState = null;
f.mSavedViewState = null;
}
}
} else if (f.mState > newState) {
//state降級處理
......
}
if (f.mState != newState) {
f.mState = newState;
}
}
複製代碼
這段代碼邏輯仍是比較長,我把註釋寫在代碼裏了。能夠看到,這個代碼寫得很巧妙,經過switch case控制,能夠一層一層地把Fragment的生命週期推動下去,好比當前fragnemt的state是Fragment.STARTED
,那麼它就只會執行performResume,若是Fragment的狀態是Fragment.INITIALIZING
,那麼就會從switch的最開始依次執行下來,把Fragment的生命週期onAttach-->onResume依次調用。 簡要說明下上面的代碼:
不少Fragment的生命週期是經過Fragment的performXxx()方法去調用的,好比:
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();
......
}
複製代碼
有些童鞋們可能會有疑問,上面只分析到了onAttach->onResume生命週期的回調,那onPause、onDestroy等方法又是何時執行的呢?咱們再看下剛纔的代碼
if (f.mState < newState) {
......
} else if (f.mState > newState) {
//state降級處理
......
}
複製代碼
答案就是在else if分支裏面,好比當Acivity鎖屏的時候,就Activity生命週期會自動回調onPause,從而觸發dispatchPause,在裏面調用moveToState(Fragment.STARTED, false); 因爲Fragment當前的狀態是RESUMED狀態,大於newState,因此就會走else if的分支,觸發相應的生命週期方法。else if分支的邏輯和state升級的差很少,這裏就再進行分析了
本文大體地從源碼的角度分析了Fragment建立、生命週期回調的過程,若是讀者對Fragment的remove
、replace
、hide
、detach
、attach
等操做有興趣的話,能夠自行分析,核心代碼主要在BackStackRecord類的run方法以及FragmentManagerImpl的moveToState方法中。