概述:
是從Android3.0開始新增的概念, 意為碎片。用來組建Activity界面的局部模塊, 也可以說一個Actiivty界面可以由多個Fragment組成。其行為與Activity很相似, 有自己對應的View, 它有自己的生命周期,接收自己的輸入事件,你可以添加或移除從運行中的activity。一個fragment必須總是嵌入在一個activity中,同時fragment的生命周期受activity的影響。本質上會產生一個FrameLayout,它加載的布局為其子布局/View
Fragmeng優點:
Fragment可以使你能夠將activity分離成多個可重用的組件,每個都有它自己的生命周期和UI。
Fragment可以輕松得創建動態靈活的UI設計,可以適應于不同的屏幕尺寸。從手機到平板電腦。
Fragment是一個獨立的模塊,緊緊地與activity綁定在一起。可以運行中動態地移除、加入、交換等。
Fragment提供一個新的方式讓你在不同的安卓設備上統一你的UI。
Fragment 解決Activity間的切換不流暢,輕量切換。
Fragment 替代TabActivity做導航,性能更好。
Fragment 在4.2.版本中新增嵌套fragmeng使用方法,能夠生成更好的界面效果。
Fragment做局部內容更新更方便,原來為了到達這一點要把多個布局放到一個activity里面,現在可以用多Fragment來代替,只有在需要的時候才加載Fragment,提高性能。
生命周期:
圖一,是Fragment的生命周期;圖二,是Activity與Fragment生命周期的對比圖:
onAttach:onAttach()在fragment與Activity關聯之后調調查用。需要注意的是,初始化fragment參數可以從getArguments()獲得,但是,當Fragment附加到Activity之后,就無法再調用setArguments()。所以除了在最開始時,其它時間都無法向初始化參數添加內容。有關Fragment參數初始化及傳遞的問題,我們會在后面的篇章中細講。
onCreate:fragment初次創建時調用。盡管它看起來像是Activity的OnCreate()函數,但這個只是用來創建Fragment的。此時的Activity還沒有創建完成,因為我們的Fragment也是Activity創建的一部分。所以如果你想在這里使用Activity中的一些資源,將會獲取不到。比如:獲取同一個Activity中其它Frament的控件實例。如果想要獲得Activity相關聯的資源,必須在onActivityCreated中獲取。
onCreateView:在這個fragment構造它的用戶接口視圖(即布局)時調用。在這里期望返回此Fragment的一個視圖層次結構。使用LayoutInflater的inflater()方法來構造實圖。代碼如下:
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.fragment3, container, false);
- }
onActivityCreated:在Activity的OnCreate()結束后,會調用此方法。所以到這里的時候,Activity已經創建完成!在這個函數中才可以使用Activity的所有資源。
onStart:當到OnStart()時,Fragment對用戶就是可見的了。但用戶還未開始與Fragment交互。在生命周期中也可以看到Fragment的OnStart()過程與Activity的OnStart()過程是綁定的。意義即是一樣的。以前你寫在Activity的OnStart()中來處理的代碼,用Fragment來實現時,依然可以放在OnStart()中來處理。
onResume:當這個fragment對用戶可見并且正在運行時調用。這是Fragment與用戶交互之前的最后一個回調。從生命周期對比中,可以看到,Fragment的OnResume與Activity的OnResume是相互綁定的,意義是一樣的。它依賴于包含它的activity的Activity.onResume。當OnResume()結束后,就可以正式與用戶交互了。
onPause:此回調與Activity的OnPause()相綁定,與Activity的OnPause()意義一樣。
onStop:這個回調與Activity的OnStop()相綁定,意義一樣。已停止的Fragment可以直接返回到OnStart()回調,然后調用OnResume()。
onDestroyView:如果Fragment即將被結束或保存,那么撤銷方向上的下一個回調將是onDestoryView()。會將在onCreateView創建的視圖與這個fragment分離。下次這個fragment若要顯示,那么將會創建新視圖。這會在onStop之后和onDestroy之前調用。這個方法的調用同onCreateView是否返回非null視圖無關。它會潛在的在這個視圖狀態被保存之后以及它被它的父視圖回收之前調用。
onDestroy:當這個fragment不再使用時調用。需要注意的是,它即使經過了onDestroy()階段,但仍然能從Activity中找到,因為它還沒有Detach。
onDetach:Fragment生命周期中最后一個回調是onDetach()。調用它以后,Fragment就不再與Activity相綁定,它也不再擁有視圖層次結構,它的所有資源都將被釋放。
常見生命周期流程:
添加Fragment對象顯示 :onAttach()-->onCreate()-->onCreateView()-->onActivityCreated()-->onstart()-->onResume()
home到桌面 :onPause()-->onStop()
回到應用 :onStart()-->onResume()
replace為其它Fragment :onPause()-->onStop()-->onDestroyView()
返回到本身的Fragment :onCreateView()-->onActivityCreated()-->onstart()-->onResume()
退出應用 :onPause()-->onstop()-->onDestroyView()-->onDestroy()-->onDetach()
有關回滾:
要使用回滾功能,只需要要使用下面兩個代碼:
在transaction.commit()之前,使用addToBackStack()將其添加到回退棧中。
在需要回退時,使用popBackStack()將最上層的操作彈出回退棧。
這里的popBackStack()是彈出默認的最上層的棧頂內容。
當棧中有多層時,我們可以根據id或TAG標識來指定彈出到的操作所在層。函數如下:
void popBackStack(int id, int flags);
void popBackStack(String name, int flags);
其中
- 參數int id是當提交變更時transaction.commit()的返回值。
- 參數string name是transaction.addToBackStack(String tag)中的tag值;
- 至于int flags有兩個取值:0或FragmentManager.POP_BACK_STACK_INCLUSIVE;
- 當取值0時,表示除了參數一指定這一層之上的所有層都退出棧,指定的這一層為棧頂層;
- 當取值POP_BACK_STACK_INCLUSIVE時,表示連著參數一指定的這一層一起退出棧;
使用popBackStack()來彈出棧內容的話,調用該方法后會將事物操作插入到FragmentManager的操作隊列,只有當輪詢到該事物時才能執行。如果想立即執行事物的話,需要使用下面幾個對應的方法:
popBackStackImmediate()
popBackStackImmediate(String tag)
popBackStackImmediate(String tag, int flag)
popBackStackImmediate(int id, int flag)
回退是以commit()提交的一次事務為單位的,而不是以其中的add,replace等等操作為單位回退的,即,如果我們在一次提交是添加了fragment2,fragment3,fragment4,那么回退時,會依據添加時的順序,將它們一個個刪除,返回到沒有添加fragment4,fragment3,fragment2的狀態。
切換fragment:
如果我們使用replace來切換頁面,那么在每次切換的時候,Fragment都會重新實例化,重新加載一邊數據,這樣非常消耗性能和用戶的數據流量。
這是因為replace操作,每次都會把Container中的現有的fragment實例清空,然后再把指定的fragment添加進去,就就造成了在切換到以前的fragment時,就會重新實例會fragment。
正確的切換方式是add(),切換時hide(),add()另一個Fragment;再次切換時,只需hide()當前,show()另一個。這樣就能做到多個Fragment切換不重新實例化
大家可能覺得這里有個問題,如果我們要show()的fragment不在最頂層怎么辦?如果不在ADD隊列的隊首,那顯然show()之后是不可見的;那豈不影響了APP邏輯。大家有這個想法是很棒的,但在APP中不存在這樣的情況,因為我們的APP的fragment是一層層ADD進去的,而且我們的fragment實例都是唯一的,用TAG來標識,當退出的時候也是一層層剝離的,所以當用戶的動作導致要添加某個fragment時,那說明這個fragment肯定是在棧頂的。