Fragment是嵌套入Activity的片段,比Activity要更為輕巧靈活,但是用起來也會(huì)相對(duì)比較麻煩一些莱找。之前在學(xué)習(xí)Fragment和實(shí)際開發(fā)中遇到一些Fragment的問題,所以就這些問題進(jìn)行了整理赦颇。
一、Fragment的初始化
Google源碼中一般采用newInstance的靜態(tài)方法來新建一個(gè)fragment赴涵,建議用setArgument的方式來傳遞參數(shù)媒怯,將所需的參數(shù)直接暴露出來,方便一起開發(fā)的同事知道需要傳什么數(shù)據(jù)髓窜。
二扇苞、屏幕旋轉(zhuǎn)帶來的問題
1、配置如下屬性寄纵,限制Fragment托管的Activity旋轉(zhuǎn)
<activity android:name= ".MainActivity"
? android:configChanges = "orientation|screenSize">
2鳖敷、保留Fragment
用setRetainInstance(true)方法保留fragment實(shí)例。fragment的retainInstance屬性值默認(rèn)是false程拭,表明fragment默認(rèn)不會(huì)被保留定踱。在屏幕旋轉(zhuǎn)時(shí),fragment的托管activity會(huì)被銷毀重建哺壶,F(xiàn)ragmentManager會(huì)銷毀隊(duì)列中的fragment視圖屋吨,接著會(huì)檢查retainInstance屬性,如果屬性是false(默認(rèn)值)山宾,F(xiàn)ragmentManager就會(huì)銷毀該fragment至扰。如果為true,該fragment的視圖會(huì)被銷毀资锰,fragment本身并不銷毀敢课,新的FragmentManager會(huì)找到它,并給他創(chuàng)建新視圖绷杜。但是直秆,如果系統(tǒng)因?yàn)閮?nèi)存不足而銷毀了托管的Activity,被保留的Fragment也會(huì)被銷毀鞭盟。
3圾结、savedInstanceState
在Activity中我們可以通過onSaveInstanceState()方法和onRestoreInstanceState()方法實(shí)現(xiàn)數(shù)據(jù)的存儲(chǔ)。
Fragment的保存機(jī)制和Activity類似齿诉,不過FragmentmyonRestoreInstanceState()方法筝野,需要在onActivityCreated()中實(shí)現(xiàn)。
4粤剧、View的保存
在視圖被銷毀之后如果想要保存View的state歇竟,需要實(shí)現(xiàn)onSaveInstanceState()方法和onRestoreInstanceState()方法。安卓自帶的View一般已經(jīng)實(shí)現(xiàn)了這個(gè)方法抵恋,開發(fā)者在使用的時(shí)候只需要添加android:freezeText=”true”屬性焕议。
關(guān)于Fragment的保存,一篇外國(guó)博文做了較為詳細(xì)的介紹弧关。The Real Best Practices to Save/Restore Activity's and Fragment's state. (StatedFragment is now deprecated)
三盅安、FragmentTransaction 的 add和remove唤锉、show和hide、replace的使用
transaction.add()
往Activity中添加一個(gè)Fragment
transaction.remove()
從Activity中移除一個(gè)Fragment宽堆,如果被移除的Fragment在沒有添加到回退棧的情況下,這個(gè)Fragment實(shí)例將會(huì)被銷毀腌紧。
transaction.replace()
使用另一個(gè)Fragment替換當(dāng)前的。
transaction.hide()
隱藏當(dāng)前的Fragment
transaction.show()
顯示之前隱藏的Fragment
替換fragment
使用replace切換:
使用replace切換回調(diào)用一下2段life cycle
05-08 07:44:30.554 2864-2864/? D/_Albert: FirstFragment:onAttch
05-08 07:44:30.554 2864-2864/? D/_Albert: FirstFragment:onCreate
05-08 07:44:30.554 2864-2864/? D/_Albert: FirstFragment:onCreateView
05-08 07:44:30.561 2864-2864/? D/_Albert: FirstFragment:onActivityCreated
05-08 07:44:30.561 2864-2864/? D/_Albert: FirstFragment:onStart
05-08 07:44:30.561 2864-2864/? D/_Albert: FirstFragment:onResume
05-08 07:44:43.010 2864-2864/? D/_Albert: FirstFragment:onPause
05-08 07:44:43.011 2864-2864/? D/_Albert: FirstFragment:onStop
05-08 07:44:43.011 2864-2864/? D/_Albert: FirstFragment:onDestoryView
05-08 07:44:43.011 2864-2864/? D/_Albert: FirstFragment:onDestory
05-08 07:44:43.011 2864-2864/? D/_Albert: FirstFragment:onDetach
05-08 07:44:43.011 2864-2864/? D/_Albert: ReplaceFragment:onAttch
05-08 07:44:43.011 2864-2864/? D/_Albert: ReplaceFragment:onCreate
05-08 07:44:43.011 2864-2864/? D/_Albert: ReplaceFragment:onCreateView
05-08 07:44:43.015 2864-2864/? D/_Albert: ReplaceFragment:onActivityCreated
05-08 07:44:43.015 2864-2864/? D/_Albert: ReplaceFragment:onStart
05-08 07:44:43.016 2864-2864/? D/_Albert: ReplaceFragment:onResume
也就是說畜隶,replace會(huì)remove掉之前的fragment壁肋,再將替換fragment,add進(jìn)去籽慢。
使用add浸遗、show、hide切換:
life cycle 如下:
05-08 08:16:44.818 3740-3740/? D/_Albert: FirstFragment:onAttch
05-08 08:16:44.819 3740-3740/? D/_Albert: FirstFragment:onCreate
05-08 08:16:44.819 3740-3740/? D/_Albert: FirstFragment:onCreateView
05-08 08:16:44.824 3740-3740/? D/_Albert: FirstFragment:onActivityCreated
05-08 08:16:44.825 3740-3740/? D/_Albert: FirstFragment:onStart
05-08 08:16:44.825 3740-3740/? D/_Albert: FirstFragment:onResume
05-08 08:16:55.383 3740-3740/? D/_Albert: SecondFragmentonAttch
05-08 08:16:55.383 3740-3740/? D/_Albert: SecondFragmentonCreate
05-08 08:16:55.383 3740-3740/? D/_Albert: SecondFragmentonCreateView
05-08 08:16:55.384 3740-3740/? D/_Albert: SecondFragment:onActivityCreated
05-08 08:16:55.384 3740-3740/? D/_Albert: SecondFragment:onStart
05-08 08:16:55.384 3740-3740/? D/_Albert: SecondFragment:onResume
以上生命周期的對(duì)比表明replace方法會(huì)remove之前的fragment箱亿,而用add搭配hide方法只是將之前的fragment做一個(gè)隱藏跛锌,并不會(huì)觸發(fā)他的life cycle。在實(shí)際開發(fā)中届惋,如果要保留一面用戶操作界面的建議不要采用replace方法去切換髓帽。
四、getActivity為null的坑
Fragment中的Context的我們一般利用getActivity()來獲取托管的Activity()作為Context使用脑豹。
而getActivity有時(shí)會(huì)null郑藏。
一種做法是保持對(duì)Activity的引用。
@Override
public voidonAttach(Activity activity) {
super.onAttach(activity);
mContext= activity;
}
getActivity()==null一般出現(xiàn)在Fragment和Activity沒有關(guān)聯(lián)的情況瘩欺。較為穩(wěn)妥的做法是找到?jīng)]關(guān)聯(lián)的原因必盖。如果確定已經(jīng)onAttach()過了,問題大多出現(xiàn)在onDetach()里面俱饿。原因可能是托管的Activity已經(jīng)被銷毀歌粥。或者Fragment的實(shí)例被刪去之后View沒有被賦值mContainerView拍埠,導(dǎo)致UI一直在失驶。