1. Fragment基本用法
為了管理Activity中的fragments,需要調(diào)用Activity中的getFragmentManager()方法。因?yàn)镕ragmentManager的API是在Android 3.0,也即API level 11開(kāi)始引入的,所以對(duì)于之前的版本,需要使用support library v4中的FragmentActivity,并且使用getSupportFragmentManager()方法。
用FragmentManager可以做的工作有:
得到Activity中存在的fragment:
使用findFragmentById()或findFragmentByTag()方法。
將fragment彈出back stack:
popBackStack():
將back stack中最后一次的fragment轉(zhuǎn)換彈出。如果沒(méi)有可以出棧的東西,返回false。
這個(gè)函數(shù)是異步的:它將彈出棧的請(qǐng)求加入隊(duì)列,但是這個(gè)動(dòng)作直到應(yīng)用回到事件循環(huán)才會(huì)執(zhí)行。
為back stack加上監(jiān)聽(tīng)器:
addOnBackStackChangedListener()
使用Fragment時(shí),可以執(zhí)行一些動(dòng)作,比如增加、移除、替換等。所有這些改變構(gòu)成一個(gè)集合,這個(gè)集合被叫做一個(gè)transaction。
可以調(diào)用FragmentTransaction中的方法來(lái)處理這個(gè)transaction.
以這樣得到FragmentTransaction類(lèi)的實(shí)例:

每個(gè)transaction是一組同時(shí)執(zhí)行的變化的集合。用add(), remove(), replace()方法,把所有需要的變化加進(jìn)去,然后調(diào)用commit()方法,將這些變化應(yīng)用。在commit()方法之前,你可以調(diào)用addToBackStack(),把這個(gè)transaction加入back stack中去,這個(gè)back stack是由activity管理的,當(dāng)用戶按返回鍵時(shí),就會(huì)回到上一個(gè)fragment的狀態(tài)。下面的代碼非常典型,用一個(gè)新的fragment取代之前的fragment,并且將之前的狀態(tài)存儲(chǔ)在back stack中。

通過(guò)調(diào)用addToBackStack(),commit()的一系列轉(zhuǎn)換作為一個(gè)transaction被存儲(chǔ)在back stack中,用戶按Back鍵可以返回上一個(gè)轉(zhuǎn)換前的狀態(tài)。
調(diào)用commit()方法并不能立即執(zhí)行transaction中包含的改變動(dòng)作,commit()方法把transaction加入activity的UI線程隊(duì)列中。
下面我們對(duì)上述代碼中出現(xiàn)的函數(shù)進(jìn)行分析,以此來(lái)逐步學(xué)習(xí)Fragment的管理機(jī)制。
getSupportFragmentManager():

該函數(shù)返回類(lèi)型是FragmentManager,F(xiàn)ragmentManager是一個(gè)抽象類(lèi),其實(shí)現(xiàn)類(lèi)是FragmentManager.FragmentManagerImpl
beginTransaction():
該函數(shù)在FragmentManagerIMpl中的源碼如下:

返回一個(gè)BackStackRecord對(duì)象,該對(duì)象是FragmentTranscation的一個(gè)子類(lèi)。
BackStackRecord的聲明如下:

該類(lèi)實(shí)現(xiàn)了一個(gè)重要的接口:FragmentManager.BackStackEntry, 該接口代表了fragment back stack的一個(gè)入口。可以用FragmentManager.getBackStackEntry()來(lái)檢索BackStackEntry。
接下來(lái)執(zhí)行transaction.replace(), 查看BackStackRecord,調(diào)用過(guò)程源碼如下:

我們發(fā)現(xiàn),replace()最終調(diào)用的函數(shù)為doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd), 將Fragment和對(duì)Fragment所進(jìn)行的操作放到op鏈表中:

該函數(shù)首先設(shè)置fragment的mFragmentManager屬性,然后再設(shè)置其mContainerId和mFragmentId,最后創(chuàng)建Op對(duì)象,然設(shè)置相應(yīng)自段,其中cmd自動(dòng)用來(lái)標(biāo)識(shí)事務(wù)的類(lèi)型,分為如下幾類(lèi):
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;
每個(gè)字段的意思可直接通過(guò)英文名稱(chēng)獲知。Op()類(lèi)是BackStackRecord中聲明的結(jié)構(gòu)體,本質(zhì)上是一個(gè)雙向鏈表的Node。addOp()如下:

該函數(shù)將Op對(duì)象添加到鏈表的末尾,并將mNumOp的值增一。
transaction.addToBackStack(null)設(shè)置了mAddToBackStack為true,源碼如下:

此函數(shù)將mAddToBackStack自段設(shè)置為true,并設(shè)置mName字段。
最后調(diào)用transaction.commit()來(lái)執(zhí)行transaction。commit()的調(diào)用過(guò)程代碼如下:

由于mAddToBackStack為true,所以會(huì)用FragmentManager為BackstackRecorder也即FragmentTransaction分配一個(gè)index,分配過(guò)程如下:

FragmentManager用mAvailBackStackIndices和mBackStackIndices兩個(gè)數(shù)組來(lái)為BackStackRecord分配Index。mAvailBackStackIndices用來(lái)存儲(chǔ)在mBackStackIndices中能夠分配的Index,mBackStackIndices則用來(lái)保存BackStackRecord。這利用兩個(gè)數(shù)組可以減少對(duì)mBackStackIndices的動(dòng)態(tài)分配大小的次數(shù),是一個(gè)以空間換時(shí)間的策略。上面的代碼首先判斷是否有可用的Index分配給BackStackRecord,若無(wú)則直接將BackStackRecord插入到mBackStackIndices;若存在的話則從mAvailBackStackIndices的隊(duì)尾取出一個(gè)index,然后設(shè)置mBackStackIndices中該index下的值。
讓我們回到commit()中,該函數(shù)最后執(zhí)行mManager.enqueAction(),源碼如下:

該函數(shù)首先進(jìn)行狀態(tài)監(jiān)測(cè),查看該Fagment所在的Activity的生命周期是否處于Saving Activity之前,因?yàn)锳ctivity保存狀態(tài)往往是由用戶離開(kāi)那個(gè)Activity所造成的,在此之后執(zhí)行commit會(huì)丟失一些狀態(tài)信息。針對(duì)這種情況,可以使用commitAllowingStateLoss().最后將BackStackRecord加入到執(zhí)行隊(duì)列中。當(dāng)?shù)谝淮瓮鶊?zhí)行
隊(duì)列中添加消息時(shí),首先會(huì)從消息隊(duì)列中所有callback屬性為mExecCommit的消息刪除,然后重新將mExecCommit添加到消息隊(duì)列。mExecCommit的定義如下:

execPendingActions()只能在主線程內(nèi)被調(diào)用,其內(nèi)部通過(guò)一個(gè)循環(huán)對(duì)mPendingActions中的Actions進(jìn)行執(zhí)行。值得注意的是,每執(zhí)行一次循環(huán),mPendingActions中的所有Action都會(huì)被添加到一個(gè)臨時(shí)數(shù)組中,然后這個(gè)數(shù)組被變量一遍以執(zhí)行數(shù)組中的每個(gè)Runnable。同時(shí),每個(gè)Runnable直接被調(diào)用了run,而不是開(kāi)個(gè)線程執(zhí)行的。當(dāng)這個(gè)Runnable在執(zhí)行的時(shí)候,mPendingActions數(shù)組可能會(huì)被添加內(nèi)容。當(dāng)某一時(shí)刻mPendingActions中的內(nèi)容為空,則while循環(huán)退出。此部分代碼如下:


由于BackstackRecorder實(shí)現(xiàn)了Runnable,我們來(lái)看看BackStackRecorder中的run(),如下所示:



addBackStackState()的源碼如下:

可以看到傳說(shuō)中的BackStack就是在這里被創(chuàng)建的, FragmentManager中的BackStack主要是用來(lái)存儲(chǔ)FragmentTransaction的。
小結(jié):
FragmentTransaction中的Op鏈用來(lái)保存add、remove、replace等action,在FragmentTransaction的run執(zhí)行時(shí),Op鏈會(huì)被變量以調(diào)整每個(gè)節(jié)點(diǎn)的內(nèi)容。
FragmentManager使用一個(gè)BackStack來(lái)管理FragmentTransaction;使用mAdded數(shù)組來(lái)添加被add的Fragment,F(xiàn)ragment的創(chuàng)建、顯示等行為都受FragmentManager的控制。
FragmentManager中的moveToState()是一個(gè)非常重要的函數(shù),在FragmentTransaction run的時(shí)候被調(diào)用。下次我們將深入這個(gè)函數(shù)。