Fragment系列文章:
1、Fragment全解析系列(一):那些年踩過的坑
2、Fragment全解析系列(二):正確的使用姿勢
3猴鲫、Fragment之我的解決方案:Fragmentation
本篇主要介紹一些Fragment使用技巧澜术。
Fragment是可以讓你的app縱享絲滑的設(shè)計(jì),如果你的app想在現(xiàn)在基礎(chǔ)上性能大幅度提高装处,并且占用內(nèi)存降低,同樣的界面Activity占用內(nèi)存比Fragment要多,響應(yīng)速度Fragment比Activty在中低端手機(jī)上快了很多穴亏,甚至能達(dá)到好幾倍!如果你的app當(dāng)前或以后有移植平板等平臺(tái)時(shí)重挑,可以讓你節(jié)省大量時(shí)間和精力嗓化。
簡陋的目錄
1、一些使用建議
2谬哀、add(), show(), hide(), replace()的那點(diǎn)事
3刺覆、關(guān)于FragmentManager你需要知道的
4、使用FragmentPagerAdapter+ViewPager的注意事項(xiàng)
5史煎、是使用單Activity+多Fragment的架構(gòu)谦屑,還是多模塊Activity+多Fragment的架構(gòu)?
作為一個(gè)穩(wěn)定的app篇梭,從后臺(tái)且回到前臺(tái)氢橙,一定會(huì)在任何情況都能恢復(fù)到離開前的頁面,并且保證數(shù)據(jù)的完整性恬偷。
如果你沒看過本系列的第一篇悍手,為了方便后面文章的介紹,先規(guī)定一個(gè)“術(shù)語”,安卓app有一種特殊情況坦康,就是 app運(yùn)行在后臺(tái)的時(shí)候竣付,系統(tǒng)資源緊張的時(shí)候?qū)е掳補(bǔ)pp的資源全部回收(殺死app的進(jìn)程),這時(shí)把a(bǔ)pp再從后臺(tái)返回到前臺(tái)時(shí)滞欠,app會(huì)重啟古胆。這種情況下文簡稱為:“內(nèi)存重啟”。(屏幕旋轉(zhuǎn)等配置變化也會(huì)造成當(dāng)前Activity重啟筛璧,本質(zhì)與“內(nèi)存重啟”類似)
<h1 id="1"> 1逸绎、一些使用建議 </h1>
1、對Fragment傳遞數(shù)據(jù)隧哮,建議使用setArguments(Bundle args)
桶良,而后在onCreate
中使用getArguments()
取出,在 “內(nèi)存重啟”前沮翔,系統(tǒng)會(huì)幫你保存數(shù)據(jù)陨帆,不會(huì)造成數(shù)據(jù)的丟失。和Activity的Intent恢復(fù)機(jī)制類似采蚀。
2疲牵、使用newInstance(參數(shù))
創(chuàng)建Fragment對象,優(yōu)點(diǎn)是調(diào)用者只需要關(guān)系傳遞的哪些數(shù)據(jù)榆鼠,而無需關(guān)心傳遞數(shù)據(jù)的Key是什么纲爸。
3、如果你需要在Fragment中用到宿主Activity對象妆够,建議在你的基類Fragment定義一個(gè)Activity的全局變量识啦,在onAttach
中初始化,這不是最好的解決辦法神妹,但這可以有效避免一些意外Crash颓哮。詳細(xì)原因參考第一篇的“getActivity()空指針”部分。
protected Activity mActivity;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.mActivity = activity;
}
<h1 id="2">2鸵荠、add(), show(), hide(), replace()的那點(diǎn)事</h1>
1冕茅、區(qū)別
show()
,hide()
最終是讓Fragment的View setVisibility
(true還是false)蛹找,不會(huì)調(diào)用生命周期姨伤;
replace()
的話會(huì)銷毀視圖,即調(diào)用onDestoryView庸疾、onCreateView等一系列生命周期乍楚;
add()
和 replace()
不要在同一個(gè)階級的FragmentManager里混搭使用。
2届慈、使用場景
如果你有一個(gè)很高的概率會(huì)再次使用當(dāng)前的Fragment炊豪,建議使用show()
凌箕,hide()
拧篮,可以提高性能词渤。
在我使用Fragment過程中,大部分情況下都是用show()
串绩,hide()
缺虐,而不是replace()
。
注意:如果你的app有大量圖片礁凡,這時(shí)更好的方式可能是replace高氮,配合你的圖片框架在Fragment視圖銷毀時(shí),回收其圖片所占的內(nèi)存顷牌。
3剪芍、onHiddenChanged的回調(diào)時(shí)機(jī)
當(dāng)使用add()
+show(),hide()
跳轉(zhuǎn)新的Fragment時(shí)窟蓝,舊的Fragment回調(diào)onHiddenChanged()
罪裹,不會(huì)回調(diào)onStop()
等生命周期方法,而新的Fragment在創(chuàng)建時(shí)是不會(huì)回調(diào)onHiddenChanged()
运挫,這點(diǎn)要切記状共。
4、Fragment重疊問題
使用show()
谁帕,hide()
帶來的一個(gè)問題就是峡继,如果你不做任何額外處理,在“內(nèi)存重啟”后匈挖,F(xiàn)ragment會(huì)重疊碾牌;(該BUG在support-v4 24.0.0+以上 官方已修復(fù))
有些小伙伴可能就是為了避免Fragment重疊問題,而選擇使用replace()
儡循,但是使用show()
舶吗,hide()
時(shí),重疊問題很簡單解決的:
- 如果你在用24.0.0+的版本贮折,不需要特殊處理裤翩,官方已經(jīng)修復(fù)該BUG;
- 如果你在使用小于24.0.0以下的v4包调榄,可以參考9行代碼讓你App內(nèi)的Fragment對重疊說再見
<h1 id="3">3踊赠、關(guān)于FragmentManager你需要知道的</h1>
FragmentManager棧視圖:
(1)每個(gè)Fragment以及宿主Activity(繼承自FragmentActivity)都會(huì)在創(chuàng)建時(shí),初始化一個(gè)FragmentManager對象每庆,處理好Fragment嵌套問題的關(guān)鍵筐带,就是理清這些不同階級的棧視圖。
下面給出一個(gè)簡要的關(guān)系圖:
(2)對于宿主Activity缤灵,getSupportFragmentManager()
獲取的FragmentActivity的FragmentManager對象;
對于Fragment伦籍,getFragmentManager()
是獲取的是父Fragment(如果沒有蓝晒,則是FragmentActivity)的FragmentManager對象,而getChildFragmentManager()
是獲取自己的FragmentManager對象帖鸦。
<h1 id="4">4芝薇、使用FragmentPagerAdapter+ViewPager的注意事項(xiàng)</h1>
使用FragmentPagerAdapter+ViewPager時(shí),切換回上一個(gè)Fragment頁面時(shí)(已經(jīng)初始化完畢)作儿,不會(huì)回調(diào)任何生命周期方法以及
onHiddenChanged()
洛二,只有setUserVisibleHint(boolean isVisibleToUser)
會(huì)被回調(diào),所以如果你想進(jìn)行一些懶加載攻锰,需要在這里處理晾嘶。在給ViewPager綁定FragmentPagerAdapter時(shí),
new FragmentPagerAdapter(fragmentManager)
的FragmentManager娶吞,一定要保證正確垒迂,如果ViewPager是Activity內(nèi)的控件,則傳遞getSupportFragmentManager()
妒蛇,如果是Fragment的控件中机断,則應(yīng)該傳遞getChildFragmentManager()
。只要記住ViewPager內(nèi)的Fragments是當(dāng)前組件的子Fragment這個(gè)原則即可材部。你不需要考慮在“內(nèi)存重啟”的情況下毫缆,去恢復(fù)的Fragments的問題,因?yàn)镕ragmentPagerAdapter已經(jīng)幫我們處理啦乐导。
<h1 id="5">5苦丁、是使用單Activity+多Fragment的架構(gòu),還是多模塊Activity+多Fragment的架構(gòu)物臂?</h1>
單Activity+多Fragment:
一個(gè)app僅有一個(gè)Activity旺拉,界面皆是Frament,Activity作為app容器使用棵磷。
優(yōu)點(diǎn):性能高蛾狗,速度最快。參考:新版知乎 仪媒、google系app
缺點(diǎn):邏輯比較復(fù)雜沉桌,尤其當(dāng)Fragment之間聯(lián)動(dòng)較多或者嵌套較深時(shí),比較復(fù)雜算吩。
多模塊Activity+多Fragment:
一個(gè)模塊用一個(gè)Activity留凭,比如
1、登錄注冊流程:
LoginActivity + 登錄Fragment + 注冊Fragment + 填寫信息Fragment + 忘記密碼Fragment
2偎巢、或者常見的數(shù)據(jù)展示流程:
DataActivity + 數(shù)據(jù)列表Fragment + 數(shù)據(jù)詳情Fragment + ...
優(yōu)點(diǎn):速度快蔼夜,相比較單Activity+多Fragment,更易維護(hù)压昼。
我的觀點(diǎn):
權(quán)衡利弊求冷,我認(rèn)為多模塊Activity+多Fragment是最合適的架構(gòu)瘤运,開發(fā)起來不是很復(fù)雜,app的性能又很高效匠题。
當(dāng)然拯坟。Fragment只是官方提供的靈活組件,請優(yōu)先遵從你的項(xiàng)目設(shè)計(jì)梧躺!真的特別復(fù)雜的界面似谁,或者單個(gè)Activity就可以完成一個(gè)流程的界面,使用Activity可能是更好的方案掠哥。
最后
如果你讀完了第一篇和這篇文章,那么我相信你使用多模塊Activity+多Fragment的架構(gòu)所遇到的坑秃诵,大部分都應(yīng)該能找到解決辦法续搀。
但是如果流程較為復(fù)雜,比如Fragment A需要啟動(dòng)一個(gè)新的Fragment B并且關(guān)閉當(dāng)前A,或者A啟動(dòng)B菠净,B在獲取數(shù)據(jù)后禁舷,想在返回到A時(shí)把數(shù)據(jù)交給A(類似Activity的startActivityForResult
),又或者你保證在Fragment轉(zhuǎn)場動(dòng)畫的情況下毅往,使用pop(tag\id)
從棧內(nèi)退出多個(gè)Fragment牵咙,或者你甚至想Fragment有一個(gè)類似Activity的SingleTask
啟動(dòng)模式,那么你可以參考下一篇攀唯,我的解決方案庫洁桌,Fragmentation。它甚至提供了一個(gè)讓你在開發(fā)時(shí)侯嘀,可以隨時(shí)查看所有階級的棧視圖的UI界面另凌。