安卓自3.0開始引入Fragment的概念痴腌,主要是為了能在不同分辯率屏幕上進(jìn)行更為動(dòng)態(tài)和靈活的UI設(shè)計(jì),讓程序更加合理和充分利用大屏幕空間臼闻。本篇將學(xué)習(xí)Fragment以下幾個(gè)知識(shí)點(diǎn):
- Fragment概要
- Fragment生命周期
- 加載Fragment方法
- 靜態(tài)加載
- 動(dòng)態(tài)加載
- Fragment與Activity之間通信
1.Fragment概要
學(xué)習(xí)Fragment的時(shí)候可以聯(lián)系之前學(xué)習(xí)過(guò)的Activity有巧,因?yàn)樗鼈冇泻芏嘞嗨泣c(diǎn):都可包含布局鹉胖,有自己的生命周期,F(xiàn)ragment可看似迷你活動(dòng)绒尊。正如Fragment的名字--碎片畜挥,它的出現(xiàn)是為了解決Android碎片化 ,它可作為Activity界面的組成部分婴谱,可在Activity運(yùn)行中實(shí)現(xiàn)動(dòng)態(tài)地加入蟹但、移除和交換。一個(gè)Activity中可同時(shí)出現(xiàn)多個(gè)Fragment谭羔,一個(gè)Fragment也可在多個(gè)Activity中使用华糖。活動(dòng)和碎片像極了夫妻瘟裸, 雖然緊密聯(lián)系但是又有獨(dú)立空間客叉,在一起讓彼此變得更好。
下面這個(gè)非常經(jīng)典的例子更直觀地說(shuō)明了Fragment作用:
2.Fragment生命周期
先來(lái)看官方文檔提供的有關(guān)Fragment生命周期的圖片景描。
是不是能發(fā)現(xiàn)Fragment和Activity的生命周期太相似了,現(xiàn)在只需要再介紹幾個(gè)Activity中沒講過(guò)的新方法:
onAttach():當(dāng)Fragment和Activity建立關(guān)聯(lián)時(shí)調(diào)用
onCreateView():當(dāng)Fragment創(chuàng)建視圖時(shí)調(diào)用
onActivityCreated():當(dāng)與Fragment相關(guān)聯(lián)的Activity完成onCreate()之后調(diào)用
onDestroyView():在Fragment中的布局被移除時(shí)調(diào)用
onDetach():當(dāng)Fragment和Activity解除關(guān)聯(lián)時(shí)調(diào)用
在上圖中畫了幾條線秀撇,可以看到Fragment周期中的狀態(tài)幾乎都是成對(duì)出現(xiàn)的超棺,所以不難理解下圖幾種變化下Fragment生命周期方法的調(diào)用順序了。
加載到Activity中的Fragment在各種變化下方法的調(diào)用順序更值得注意呵燕。需要提一句的是棠绘,Activity的FragmentManager負(fù)責(zé)調(diào)用隊(duì)列中Fragment的生命周期方法,只要Fragment的狀態(tài)與Activity的狀態(tài)保持了同步再扭,托管Activity的FragmentManager便會(huì)繼續(xù)調(diào)用其他生命周期方法以繼續(xù)保持Fragment與Activity的狀態(tài)一致氧苍。
Fragment生命周期與Activity生命周期的一個(gè)關(guān)鍵區(qū)別就在于,F(xiàn)ragment的生命周期方法是由托管Activity而不是操作系統(tǒng)調(diào)用的泛范。Activity中生命周期方法都是protected让虐,而Fragment都是public,也能印證了這一點(diǎn)罢荡,因?yàn)锳ctivity需要調(diào)用Fragment那些方法并管理它赡突。
3.加載Fragment方法
現(xiàn)在就來(lái)學(xué)習(xí)如何在Activity中加載Fragment。
(1)靜態(tài)加載:在托管Activity的layout文件中聲明Fragment
靜態(tài)加載Fragment大致過(guò)程如圖区赵,分成四步:
下面通過(guò)一個(gè)簡(jiǎn)單的例子感受Fragment靜態(tài)加載到Activity的過(guò)程惭缰。
第一步:新建frag_layout.xml,為Fragment指定一個(gè)布局笼才,這里簡(jiǎn)單的放一個(gè)TextView和一個(gè)Button漱受。
第二步:新建一個(gè)MyFragment類并繼承Fragment,這里引用android.app包下的就可以骡送,另一個(gè)包下主要用于兼容低版本的安卓系統(tǒng)昂羡。然后重寫onCreateView()方法絮记,這個(gè)方法里通過(guò)LayoutInflater的inflate()方法將剛剛定義的frag_layout布局加載進(jìn)來(lái)并得到一個(gè)View,再return這個(gè)View紧憾。
第三步:新建mian.xml到千,作為Activity的布局,使用< fragment>標(biāo)簽添加碎片赴穗,并且一定要有android:name屬性且值為被加載的Fragment類的包名.類名完整形式憔四。
第四步:在MainActivity中加載main布局。現(xiàn)在MyFragment就完成了靜態(tài)加載到MainActivity中般眉,這時(shí)碎片里的控件自然也是活動(dòng)的一個(gè)部分了赵,可直接在活動(dòng)中獲取到Button的實(shí)例,來(lái)注冊(cè)點(diǎn)擊事件了甸赃。
運(yùn)行一下看看能不能達(dá)到效果:
(2)動(dòng)態(tài)加載:在托管Activity通過(guò)代碼動(dòng)態(tài)添加
動(dòng)態(tài)加載的代碼也非常簡(jiǎn)單柿汛,直接看例子。修改main.xml埠对,將整個(gè)< fragment>刪掉络断。但還保留一個(gè)LinerLayout的空間并且還給了Id,為何這樣做项玛?馬上揭秘貌笨。
接下來(lái)在MainActivity中添加幾行代碼:
可將整個(gè)過(guò)程大致分為三個(gè)步驟:
第一步,先用getFragmentManager()方法獲取一個(gè)FragmentManager對(duì)象襟沮,再通過(guò)它的beginTransaction()獲取一個(gè)FragmentTransaction的實(shí)例锥惋。
第二步,用beginTransaction.add()方法將MyFragemnt實(shí)例添加到main布局里L(fēng)inearLayout里开伏,終于知道之前鋪墊的Id是怎么回事了膀跌。一定要注意,add()方法里的第一個(gè)參數(shù)是容器視圖資源Id固灵,而不是layout捅伤。容器視圖資源Id有兩個(gè)作用:告知FragmentManager,碎片視圖應(yīng)該出現(xiàn)在活動(dòng)視圖的什么地方巫玻;它也是FragmentManager隊(duì)列中碎片的唯一標(biāo)識(shí)符暑认。而靜態(tài)加載時(shí)碎片的唯一標(biāo)識(shí)符正是在活動(dòng)布局里< fragment>下的id。
第三步:調(diào)用beginTransaction.commit()提交大审。另外蘸际,如果允許用戶通過(guò)按下返回按鍵返回到前一個(gè)Fragment狀態(tài),在調(diào)用commit()之前先調(diào)用addToBackStack(true)方法徒扶。
這里注意到動(dòng)態(tài)加載進(jìn)來(lái)的Fragment里的控件并不能直接在活動(dòng)中findViewById得到粮彤,那么如何實(shí)現(xiàn)點(diǎn)擊效果呢,學(xué)完下一個(gè)知識(shí)點(diǎn)就有辦法了。
4.Fragment與Activity之間通信
在活動(dòng)中可以通過(guò)調(diào)用FragmentManager的findFragmentById()方法來(lái)得到相應(yīng)碎片的實(shí)例导坟,繼而可以調(diào)用碎片里的方法屿良。以上面demo舉例,如果想得到靜態(tài)加載碎片的實(shí)例惫周,可在MainActivity添加代碼如下:
MyFragment myFragment = (MyFragment)getFragmentManager(). findFragmentById(R.id.fragment);
如果想得到動(dòng)態(tài)加載碎片的實(shí)例尘惧,代碼如下:
MyFragment myFragment = (MyFragment)fragmentManager(). findFragmentById(R.id.layout);
在碎片中也可以通過(guò)調(diào)用getActivity()方法來(lái)得到和當(dāng)前碎片相關(guān)聯(lián)的活動(dòng)實(shí)例,這樣調(diào)用活動(dòng)里的方法就變得輕而易舉了递递。比如想在MyFragment得到MainActivity的實(shí)例:
MainActivity activity=(MainActivity)getActivity();
于是碎片和活動(dòng)可以很方便地進(jìn)行通信了喷橙。再想一想碎片和碎片之間如何進(jìn)行通信?先在一個(gè)碎片中可以得到與它相關(guān)聯(lián)的活動(dòng)登舞,然后再通過(guò)這個(gè)活動(dòng)去獲取另外一個(gè)碎片的實(shí)例贰逾,這樣實(shí)現(xiàn)了不同碎片之間的通信了。
現(xiàn)在你有沒有想到解決之前那個(gè)問(wèn)題的辦法呢菠秒?可以這樣做疙剑,修改MyFragment,代碼如下圖所示:
現(xiàn)在按鈕點(diǎn)擊就又有響應(yīng)了践叠!其實(shí)在實(shí)際開發(fā)中言缤,如果某一板塊每次用到都需要相同的功能,就完全可以在碎片中實(shí)現(xiàn)需求禁灼,而不必在活動(dòng)中重復(fù)代碼管挟,這樣可以提高代碼的復(fù)用性。
> 下一篇預(yù)告:數(shù)據(jù)存儲(chǔ)篇