Fragment的陷阱
現(xiàn)在主流的APP都會(huì)使用到Fragment,相信你也一定使用過,今天為大家介紹一下我曾經(jīng)踏過的一個(gè)關(guān)于Fragment的坑。
以前做過的一個(gè)項(xiàng)目,F(xiàn)ragment嵌套高德地圖,當(dāng)再次進(jìn)入Fragment的時(shí)候,會(huì)出現(xiàn)奇怪的現(xiàn)象。嵌套的地圖會(huì)出現(xiàn)滑動(dòng)不動(dòng)的情況,起先還以為是高德的bug呢,經(jīng)過一番研究,終確定這是一個(gè)坑。
先對(duì)Fragment做一個(gè)簡(jiǎn)單的介紹,借用csdn上朋友寫的一段內(nèi)容。
Android在3.0中引入了fragments的概念,主要目的是用在大屏幕設(shè)備上--例如平板電腦上,支持更加動(dòng)態(tài)和靈活的UI設(shè)計(jì)。平板電腦的屏幕要比手機(jī)的大得多,有更多的空間來放更多的UI組件,并且這些組件之間會(huì)產(chǎn)生更多的交互。Fragment允許這樣的一種設(shè)計(jì),而不需要你親自來管理 viewhierarchy的復(fù)雜變化。 通過將activity的布局分散到fragment中, 你可以在運(yùn)行時(shí)修改activity的外觀,并在由activity管理的back stack中保存那些變化。
使用過Fragment的同學(xué)都知道,它的使用相當(dāng)?shù)暮?jiǎn)單,基本上和Activity中一樣,就是生命周期函數(shù)稍稍多了點(diǎn)。今天不是介紹Fragment如何使用,而是介紹一個(gè)Fragment中的一個(gè)坑?,F(xiàn)在相當(dāng)多的APP都有以下三種設(shè)計(jì)風(fēng)格。
一、底部TAB,一般3-5個(gè),點(diǎn)擊某個(gè)TAB,上面頁面也隨之切換,如QQ、騰訊微博、新浪微博。早期的時(shí)候Android開發(fā)者們都會(huì)使用TabActivity去實(shí)現(xiàn),但是TabActivity存在一些問題,也不符合Andoid的單窗口設(shè)計(jì)的原則,所以已經(jīng)被廢棄,不推薦大家繼續(xù)使用。如有業(yè)務(wù)需求,請(qǐng)優(yōu)先考慮使用Fragement。
二、頂部TAB,一般也是3-5個(gè)左右,相對(duì)于底部TAB風(fēng)格,頂部TAB一般會(huì)引入ViewPager + Fragment的實(shí)現(xiàn)方式,這樣可以做到左右切換,如微信。
三、側(cè)邊TAB,也就是SlidingMenu + Fragment或者M(jìn)enuDrawer + Fragment。這種風(fēng)格自去年起,風(fēng)靡的一發(fā)不可收拾,前段時(shí)間干貨分享講的一期就是這個(gè),代碼也開源在了Github上,有興趣的朋友可以下載了解下。出門右轉(zhuǎn),查看歷史消息《一個(gè)比較酷的項(xiàng)目界面分享,干貨十足》。
上述三種風(fēng)格中使用到的Fragment,一般很容易會(huì)被大家忽略了一個(gè)問題。那就是當(dāng)和Fragment關(guān)聯(lián)的view hierarchy正在被移除時(shí),不會(huì)執(zhí)行onDestroy()方法,而是會(huì)調(diào)用onDestroyView()。比如上述的風(fēng)格二ViewPager + Fragment,默認(rèn)情況下當(dāng)ViewPager滑動(dòng)到第三頁的時(shí)候,***頁的Fragment就會(huì)執(zhí)行onDestroyView,當(dāng)再次滑動(dòng)到第二頁的時(shí)候,***頁的Fragment的onCreateView又會(huì)重新執(zhí)行繪制頁面。伴隨而來的問題就是成員變量要重新賦值一次,辛苦耗時(shí)加載出來的頁面又要重新加載一次,這樣也就給內(nèi)存增加了無意思的壓力,用戶體驗(yàn)上也不大友好,尤其在有網(wǎng)絡(luò)請(qǐng)求等開銷時(shí)長比較長的情況下。
那有沒有上面解決辦法呢?答案是肯定的。onDestroyView的執(zhí)行和Activity的onDestroy不一樣,不會(huì)銷毀當(dāng)前的頁面,所以Fragment的所有成員變量的引用都還在。那就好辦了,我們?cè)趏nCreateView的時(shí)候,先判斷該取到的數(shù)據(jù)是否為空,比如Fragment的根視圖rootView,網(wǎng)絡(luò)請(qǐng)求獲取到的數(shù)據(jù)等,如果不為空就不用再次執(zhí)行。這樣一來也就避免了上述說的那些問題的存在了。
但是需要注意的一點(diǎn)就是,如果重用rootView的話,一定要記得在onDestroyView里面把rootView先給移除掉,因?yàn)橐呀?jīng)有過父布局的View是不能再次添加到另一個(gè)新的父布局上面的。代碼如下
這樣也就解決了最前面我遇到的那個(gè)bug,由于每次進(jìn)入都會(huì)創(chuàng)建一個(gè)MapView,很多地圖疊在了一起,所以就出現(xiàn)了"滑不動(dòng)"的奇怪現(xiàn)象。
今天分享的只是一個(gè)優(yōu)化策略罷了,希望能幫助到你。
本文鏈接:http://my.oschina.net/u/1171391/blog/295649