【Android】Fragment懶加載(只加載一次)

Fragment懶加載

封裝的支持以下的功能:

1.支持?jǐn)?shù)據(jù)的懶加載并且只加載一次

2.提供 Fragment 可見與不可見時(shí)回調(diào)陶因,支持你在這里進(jìn)行一些 ui 操作淀弹,如顯示/隱藏加載框

3.支持 view 的復(fù)用籽前,防止與 ViewPager 使用時(shí)出現(xiàn)重復(fù)創(chuàng)建 view 的問題

第一點(diǎn)應(yīng)該是比較需要且常用的一點(diǎn)诱鞠,之前那篇博客里沒有考慮到這點(diǎn)應(yīng)用場(chǎng)景是我的疏忽闹瞧。稍微講解一下欺劳,有些時(shí)候唧取,我們打開一個(gè) Fragment 頁面時(shí),希望它是在可見時(shí)才去加載數(shù)據(jù)划提,也就是不要在后臺(tái)就開始加載數(shù)據(jù)枫弟,而且,我們也希望加載數(shù)據(jù)的操作只是第一次打開該 Fragment 時(shí)才進(jìn)行的操作鹏往,以后如果再重新打開該 Fragment 的話淡诗,就不要再重復(fù)的去加載數(shù)據(jù)了。

具體點(diǎn)說伊履,F(xiàn)ragment 和 ViewPager 一起用時(shí)袜漩,由于 ViewPager 的緩存機(jī)制,在打開一個(gè) Fragment 時(shí)湾碎,它旁邊的幾個(gè) Fragment 其實(shí)也已經(jīng)被創(chuàng)建了宙攻,如果我們是在 Fragment 的?onCreat()?或者?onCreateView()?里去跟服務(wù)器交互,下載界面數(shù)據(jù)介褥,那么這時(shí)這些已經(jīng)被創(chuàng)建的 Fragment座掘,就都會(huì)出現(xiàn)在后臺(tái)下載數(shù)據(jù)的情況了递惋。所以我們通常需要在?setUserVisibleHint()?里去判斷當(dāng)前 Fragment 是否可見,可見時(shí)再去下載數(shù)據(jù)溢陪,但是這樣還是會(huì)出現(xiàn)一個(gè)問題萍虽,就是每次可見時(shí)都會(huì)重復(fù)去下載數(shù)據(jù),我們希望的是只有第一次可見時(shí)才需要去下載形真,那么就還需要再做一些判斷杉编。這就是要封裝個(gè)基類來做這些事了,具體代碼見后面咆霜。

即使我們?cè)?setUserVisibleHint()?做了很多判斷邓馒,實(shí)現(xiàn)了可見時(shí)加載并且只有第一次可見時(shí)才加載,可能還是會(huì)遇到其他問題蛾坯。比如說光酣,我下載完數(shù)據(jù)就直接需要對(duì) ui 進(jìn)行操作,將數(shù)據(jù)展示出來脉课,但有時(shí)卻報(bào)了 ui 控件 null 異常救军,這是因?yàn)?setUserVisibleHint()?有可能在?onCreateView()?創(chuàng)建 view 之前調(diào)用,而且數(shù)據(jù)加載時(shí)間很短倘零,這就可能出現(xiàn) null 異常了唱遭,那么我們還需要再去做些判斷,保證在數(shù)據(jù)下載完后 ui 控件已經(jīng)創(chuàng)建完成呈驶。

除了懶加載拷泽,只加載一次的需求外,可能我們還需要每次 Fragment 的打開或關(guān)閉時(shí)顯示數(shù)據(jù)加載進(jìn)度俐东。對(duì)吧,我們打開一個(gè) Fragment 時(shí)订晌,如果數(shù)據(jù)還沒下載完虏辫,那么應(yīng)該給個(gè)下載進(jìn)度或者加載框提示,如果這個(gè)時(shí)候打開了新的 Fragment 頁面锈拨,然后又重新返回時(shí)砌庄,如果數(shù)據(jù)還沒加載完,那么也還應(yīng)該繼續(xù)給提示奕枢,對(duì)吧娄昆。這就需要有個(gè) Fragment 可見與不可見時(shí)觸發(fā)的回調(diào)方法,并且該方法還得保證是在 view 創(chuàng)建完后才觸發(fā)的缝彬,這樣才能支持對(duì) ui 進(jìn)行操作萌焰。

以上,就是我們封裝的 BaseFragment 基類要干的活了谷浅。下面上代碼扒俯。

代碼

/** * Created by dasu on 2016/9/27. * * Fragment基類奶卓,封裝了懶加載的實(shí)現(xiàn) * * 1、Viewpager + Fragment情況下撼玄,fragment的生命周期因Viewpager的緩存機(jī)制而失去了具體意義 * 該抽象類自定義新的回調(diào)方法夺姑,當(dāng)fragment可見狀態(tài)改變時(shí)會(huì)觸發(fā)的回調(diào)方法,和 Fragment 第一次可見時(shí)會(huì)回調(diào)的方法 * *@see#onFragmentVisibleChange(boolean) *@see#onFragmentFirstVisible() */publicabstractclassBaseFragmentextendsFragment{privatestaticfinalString TAG = BaseFragment.class.getSimpleName();privatebooleanisFragmentVisible;privatebooleanisReuseView;privatebooleanisFirstVisible;privateView rootView;//setUserVisibleHint()在Fragment創(chuàng)建時(shí)會(huì)先被調(diào)用一次掌猛,傳入isVisibleToUser = false//如果當(dāng)前Fragment可見盏浙,那么setUserVisibleHint()會(huì)再次被調(diào)用一次,傳入isVisibleToUser = true//如果Fragment從可見->不可見荔茬,那么setUserVisibleHint()也會(huì)被調(diào)用废膘,傳入isVisibleToUser = false//總結(jié):setUserVisibleHint()除了Fragment的可見狀態(tài)發(fā)生變化時(shí)會(huì)被回調(diào)外,在new Fragment()時(shí)也會(huì)被回調(diào)//如果我們需要在 Fragment 可見與不可見時(shí)干點(diǎn)事兔院,用這個(gè)的話就會(huì)有多余的回調(diào)了殖卑,那么就需要重新封裝一個(gè)@OverridepublicvoidsetUserVisibleHint(booleanisVisibleToUser){super.setUserVisibleHint(isVisibleToUser);//setUserVisibleHint()有可能在fragment的生命周期外被調(diào)用if(rootView ==null) {return;? ? ? ? }if(isFirstVisible && isVisibleToUser) {? ? ? ? ? ? onFragmentFirstVisible();? ? ? ? ? ? isFirstVisible =false;? ? ? ? }if(isVisibleToUser) {? ? ? ? ? ? onFragmentVisibleChange(true);? ? ? ? ? ? isFragmentVisible =true;return;? ? ? ? }if(isFragmentVisible) {? ? ? ? ? ? isFragmentVisible =false;? ? ? ? ? ? onFragmentVisibleChange(false);? ? ? ? }? ? }@OverridepublicvoidonCreate(@Nullable Bundle savedInstanceState){super.onCreate(savedInstanceState);? ? ? ? initVariable();? ? }@OverridepublicvoidonViewCreated(View view, @Nullable Bundle savedInstanceState){//如果setUserVisibleHint()在rootView創(chuàng)建前調(diào)用時(shí),那么//就等到rootView創(chuàng)建完后才回調(diào)onFragmentVisibleChange(true)//保證onFragmentVisibleChange()的回調(diào)發(fā)生在rootView創(chuàng)建完成之后坊萝,以便支持ui操作if(rootView ==null) {? ? ? ? ? ? rootView = view;if(getUserVisibleHint()) {if(isFirstVisible) {? ? ? ? ? ? ? ? ? ? onFragmentFirstVisible();? ? ? ? ? ? ? ? ? ? isFirstVisible =false;? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? onFragmentVisibleChange(true);? ? ? ? ? ? ? ? isFragmentVisible =true;? ? ? ? ? ? }? ? ? ? }super.onViewCreated(isReuseView ? rootView : view, savedInstanceState);? ? }@OverridepublicvoidonDestroyView(){super.onDestroyView();? ? }@OverridepublicvoidonDestroy(){super.onDestroy();? ? ? ? initVariable();? ? }privatevoidinitVariable(){? ? ? ? isFirstVisible =true;? ? ? ? isFragmentVisible =false;? ? ? ? rootView =null;? ? ? ? isReuseView =true;? ? }/**? ? * 設(shè)置是否使用 view 的復(fù)用孵稽,默認(rèn)開啟? ? * view 的復(fù)用是指,ViewPager 在銷毀和重建 Fragment 時(shí)會(huì)不斷調(diào)用 onCreateView() -> onDestroyView()? ? ? * 之間的生命函數(shù)十偶,這樣可能會(huì)出現(xiàn)重復(fù)創(chuàng)建 view 的情況菩鲜,導(dǎo)致界面上顯示多個(gè)相同的 Fragment? ? * view 的復(fù)用其實(shí)就是指保存第一次創(chuàng)建的 view,后面再 onCreateView() 時(shí)直接返回第一次創(chuàng)建的 view? ? *? ? *@paramisReuse? ? */protectedvoidreuseView(booleanisReuse){? ? ? ? isReuseView = isReuse;? ? }/**? ? * 去除setUserVisibleHint()多余的回調(diào)場(chǎng)景惦积,保證只有當(dāng)fragment可見狀態(tài)發(fā)生變化時(shí)才回調(diào)? ? * 回調(diào)時(shí)機(jī)在view創(chuàng)建完后接校,所以支持ui操作,解決在setUserVisibleHint()里進(jìn)行ui操作有可能報(bào)null異常的問題? ? *? ? * 可在該回調(diào)方法里進(jìn)行一些ui顯示與隱藏狮崩,比如加載框的顯示和隱藏? ? *? ? *@paramisVisible true? 不可見 -> 可見? ? *? ? ? ? ? ? ? ? ? false 可見? -> 不可見? ? */protectedvoidonFragmentVisibleChange(booleanisVisible){? ? }/**

? ? * 在fragment首次可見時(shí)回調(diào)蛛勉,可在這里進(jìn)行加載數(shù)據(jù),保證只在第一次打開Fragment時(shí)才會(huì)加載數(shù)據(jù)睦柴,

? ? * 這樣就可以防止每次進(jìn)入都重復(fù)加載數(shù)據(jù)

? ? * 該方法會(huì)在 onFragmentVisibleChange() 之前調(diào)用诽凌,所以第一次打開時(shí),可以用一個(gè)全局變量表示數(shù)據(jù)下載狀態(tài)坦敌,

? ? * 然后在該方法內(nèi)將狀態(tài)設(shè)置為下載狀態(tài)侣诵,接著去執(zhí)行下載的任務(wù)

? ? * 最后在 onFragmentVisibleChange() 里根據(jù)數(shù)據(jù)下載狀態(tài)來控制下載進(jìn)度ui控件的顯示與隱藏

? ? */protectedvoidonFragmentFirstVisible(){? ? }protectedbooleanisFragmentVisible(){returnisFragmentVisible;? ? }}

使用方法

使用很簡(jiǎn)單,新建你需要的 Fragment 類繼承自該 BaseFragment狱窘,然后重寫兩個(gè)回調(diào)方法杜顺,根據(jù)你的需要在回調(diào)方法里進(jìn)行相應(yīng)的操作比如下載數(shù)據(jù)等即可。

例如:

publicclassCategoryFragmentextendsBaseFragment{privatestaticfinalStringTAG=CategoryFragment.class.getSimpleName();@Nullable@OverridepublicViewonCreateView(LayoutInflaterinflater,@NullableViewGroupcontainer,@NullableBundlesavedInstanceState) {Viewview = inflater.inflate(R.layout.fragment_category, container,false);? ? ? ? initView(view);returnview;? ? }@Overrideprotectedvoid onFragmentVisibleChange(boolean isVisible) {if(isVisible) {//更新界面數(shù)據(jù)蘸炸,如果數(shù)據(jù)還在下載中躬络,就顯示加載框notifyDataSetChanged();if(mRefreshState ==STATE_REFRESHING) {? ? ? ? ? ? ? ? mRefreshListener.onRefreshing();? ? ? ? ? ? }? ? ? ? }else{//關(guān)閉加載框mRefreshListener.onRefreshFinish();? ? ? ? }? ? }@Overrideprotectedvoid onFragmentFirstVisible() {//去服務(wù)器下載數(shù)據(jù)mRefreshState =STATE_REFRESHING;? ? ? ? mCategoryController.loadBaseData();? ? }}

注意事項(xiàng)

如果想要讓 fragment 的布局復(fù)用成功,需要重寫 viewpager 的適配器里的?destroyItem()?方法搭儒,將 super 去掉洗鸵,也就是不銷毀 view越锈。

如果出現(xiàn)切換回來或不相鄰的Tab切換時(shí)導(dǎo)致空白界面的問題,解決方法:在 onCreateView中復(fù)用布局 + ViewPager 的適配器中復(fù)寫 destroyItem() 方法去掉 super膘滨。


http://www.cnblogs.com/dasusu/p/6745032.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末甘凭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子火邓,更是在濱河造成了極大的恐慌丹弱,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铲咨,死亡現(xiàn)場(chǎng)離奇詭異躲胳,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)纤勒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門坯苹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人摇天,你說我怎么就攤上這事粹湃。” “怎么了泉坐?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵为鳄,是天一觀的道長。 經(jīng)常有香客問我腕让,道長孤钦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任纯丸,我火速辦了婚禮偏形,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘觉鼻。我一直安慰自己俊扭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布滑凉。 她就那樣靜靜地躺著统扳,像睡著了一般喘帚。 火紅的嫁衣襯著肌膚如雪畅姊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天吹由,我揣著相機(jī)與錄音若未,去河邊找鬼。 笑死倾鲫,一個(gè)胖子當(dāng)著我的面吹牛粗合,可吹牛的內(nèi)容都是我干的萍嬉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼隙疚,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼壤追!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起供屉,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤行冰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后伶丐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悼做,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年哗魂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肛走。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡录别,死狀恐怖朽色,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情庶灿,我是刑警寧澤纵搁,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站往踢,受9級(jí)特大地震影響腾誉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜峻呕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一利职、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瘦癌,春花似錦猪贪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至斤寇,卻和暖如春桶癣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背娘锁。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國打工牙寞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓间雀,卻偏偏與公主長得像悔详,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子惹挟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354