我們?cè)陂_發(fā)中,常常會(huì)遇到一個(gè)Activity中,會(huì)有多個(gè)Fragment進(jìn)行來回切換的情況。大多數(shù)情況下,我們?yōu)榱吮苊庵貜?fù)創(chuàng)建相同的Fragment,會(huì)使用FragmentManager對(duì)這些Fragment進(jìn)行添加、移除、隱藏、顯示等操作。操作完成后,再執(zhí)行一次FragmentTransaction.commit()。今天就來介紹一下FragmentTransaction的commit()方法。
FragmentTransaction事務(wù)
- 我們通過需要對(duì)一個(gè)個(gè)Fragment進(jìn)行操作,比如動(dòng)態(tài)添加、替換、隱藏等。這一系列的操作(a series of edit operations on the Fragments)構(gòu)成一個(gè)集合,我們稱為事務(wù)Transaction。
- FragmentManager中用來處理這些事務(wù)的類是FragmentTransaction。在Activity中,通過getSupportFragmentManager()獲取到FragmentManager之后,調(diào)用beginTransaction()就可以得到一個(gè)FragmentTransaction對(duì)象。
動(dòng)態(tài)操作Fragment的步驟
- Activity中通過getSupportFragmentManager().beginTransaction()獲取到一個(gè)FragmentTransaction對(duì)象。注意,每beginTransaction一次就會(huì)創(chuàng)建一個(gè)新的FragmentTransaction對(duì)象。
- 使用獲取到的FragmentTransaction對(duì)象,進(jìn)行Fragment的一系列操作。比如add、hide、replace、remove等等。
- 操作完成后,將整個(gè)事務(wù)FragmentTransaction提交。提交的方式有4種,后面會(huì)介紹區(qū)別。
Activity的BackStack
- 這里需要提及一下管理Activity的棧BackStack。我們知道一個(gè)應(yīng)用包含多個(gè)Activity,我們按照一定順序啟動(dòng)Activity。每啟動(dòng)一個(gè)新的Activity,舊的Activity就會(huì)被放到BackStack中。這樣,當(dāng)我們點(diǎn)擊返回鍵或者調(diào)用finish的時(shí)候,之前的Activity會(huì)依次從BackStack中取出,順序就是后進(jìn)先出。
- 當(dāng)使用Fragment的時(shí)候,我們可能會(huì)遇到這種需求:一個(gè)Activity中包含多個(gè)Fragment,依次根據(jù)用戶點(diǎn)擊添加和展示多個(gè)Fragment。當(dāng)用戶點(diǎn)擊返回鍵的時(shí)候,Activity不變,但是Fragment需要依次退回到上一個(gè)Fragment。
- 如果有這種需求,那么在commit()方法之前,需要調(diào)用addToBackStack(),把這個(gè)transaction增加back stack中去。這個(gè)back stack是由activity管理的。當(dāng)用戶按返回鍵時(shí),就會(huì)回到上一個(gè)fragment的狀態(tài)。
FragmentTransaction提交和Activity狀態(tài)保存的關(guān)系
- Activity的狀態(tài)保存
一般情況,當(dāng)Activity調(diào)用onPause()和onStop()方法后,activity實(shí)例仍然存在于內(nèi)存中, activity的所有信息和狀態(tài)數(shù)據(jù)不會(huì)消失。當(dāng)activity重新回到前臺(tái)之后, 所有的改變都會(huì)得到保留。
但是當(dāng)系統(tǒng)內(nèi)存不足的時(shí)候,就會(huì)把內(nèi)存中Activity的對(duì)象進(jìn)行銷毀。這種情況下,為了保存Activity中緩存的數(shù)據(jù),系統(tǒng)會(huì)回調(diào)Activity的onSaveInstanceState()方法。我們可以在這方法里把我們希望下次打開Activity后,需要恢復(fù)的數(shù)據(jù)保存下來。這樣當(dāng)重新打開Activity,在onCreate方法中,可以從傳入?yún)?shù)Bundle savedInstanceState中獲取到我們保存的數(shù)據(jù)。
這就是Activity的狀態(tài)保存。 - Activity執(zhí)行完onSaveInstanceState()方法后不能再執(zhí)行commit()方法
Fragment的提交分為兩大類:commit(或者commitNow)、commitAllowingStateLoss(或者commitNowAllowingStateLoss)。前者的提交必須在Activity狀態(tài)保存之前,否則就會(huì)報(bào)錯(cuò)。后者的提交不用關(guān)心Activity的狀態(tài)是否保存。雖然在Activity狀態(tài)保存之后再提交不會(huì)拋異常,但是本次提交可能會(huì)丟失。也就是說使用后者,你的Activity在恢復(fù)的時(shí)候,很可能沒有保存之前FragmentTransaction提交操作。所以如果你能接受界面恢復(fù)之后和之前不一樣,那就用后者,否則就用前者,但是一定要在onSaveInstanceState之前提交。
commit和FragmentManager的executePendingTransactions()
- 用add(), remove(), replace()方法,把全部須要的變化加進(jìn)去,然后調(diào)用commit()方法。就可以將這些變化提交,但是提交的這些操作不會(huì)被立即執(zhí)行。
- FragmentManager的executePendingTransactions()方法。這個(gè)方法就是幫你在FragmentTransaction commit之后,立即去執(zhí)行操作。包括創(chuàng)建Fragment,執(zhí)行Fragment的各種生命周期。
4種提交的區(qū)別
對(duì)fragment的一系列操作完成之后,需要提交才能讓這些操作生效。提交供分為4種,下面介紹一下區(qū)別。
- commit()
- 安排當(dāng)前事務(wù)FragmentTransaction進(jìn)行提交。但是提交后Fragment不會(huì)立即創(chuàng)建,而是由主線程異步來創(chuàng)建。也就是說使用commit()之后,你的Fragment不會(huì)被立即加入到Activity中。
- 本次提交,必須在Activity的onSaveInstanceState調(diào)用之前提交。否則會(huì)拋異常。
- commitAllowingStateLoss
和commit類似。但是如果本次是在Activity的onSaveInstanceState調(diào)用之后,那么本次提交記錄在Activity恢復(fù)的時(shí)候,可能不被保存。 - commitNow()
- 將事務(wù)立即提交。所有添加的Fragment會(huì)被立即初始化,并開始生命周期。所有被移除的Fragment將會(huì)被立即移除。
- 調(diào)用這個(gè)方法,相當(dāng)于調(diào)用commit,然后調(diào)用FragmentManager的executePendingTransactions()。
- commitNowAllowingStateLoss()
和commitNow類似。但是如果在在Activity的onSaveInstanceState調(diào)用之后,那么本次提交記錄在Activity恢復(fù)的時(shí)候,可能不被保存。
每個(gè)FragmentTransaction只能提交commit一次
- 包括commit、commitNow、commitAllowingStateLoss、commitNowAllowingStateLoss。提交完一次之后,再commit就會(huì)拋出異常。
- 也就是說不要每進(jìn)行一個(gè)操作就commit一次,應(yīng)該把多個(gè)操作都在FragmentTransact