一. Fragment簡介
我們都知道,Android上的界面展示都是通過Activity實(shí)現(xiàn)的塞栅,Activity實(shí)在是太常用了她君,我相信大家都已經(jīng)非常熟悉了,這里就不再贅述警没。但是Activity也有它的局限性匈辱,同樣的界面在手機(jī)上顯示可能很好看,在平板上就未必了杀迹,因?yàn)槠桨宓钠聊环浅4笸隽常謾C(jī)的界面放在平板上可能會有過分被拉長、控件間距過大等情況树酪。這個(gè)時(shí)候更好的體驗(yàn)效果是在Activity中嵌入"小Activity"浅碾,然后每個(gè)"小Activity"又可以擁有自己的布局。因此嗅回,我們今天的主角Fragment登場了及穗。
Android在3.0版本引入了Fragment功能摧茴, Fragment根據(jù)詞海的翻譯可以譯為:碎片绵载、片段。Fragment不可以單獨(dú)存在,是一種可以嵌入在活動當(dāng)中的UI片段娃豹,它能讓程序更加合理和充分地利用大屏幕焚虱,相比Activity更輕量級、更靈活懂版。它非常類似于Activity鹃栽,可以像Activity一樣包含布局。Fragment通常是嵌套在Activity中使用的躯畴。
Fragment是在3.0版本引入的民鼓,如果你使用的是3.0之前的系統(tǒng),需要先導(dǎo)入android-support-v4的jar包才能使用Fragment功能蓬抄。
二. Fragment的生命周期
- 每一個(gè)fragments 都有自己的一套生命周期回調(diào)方法和處理自己的用戶輸入事件丰嘉。 對應(yīng)生命周期可參考下圖:
因?yàn)镕ragment必須嵌入在Acitivity中使用,所以Fragment的生命周期和它所在的Activity是密切相關(guān)的嚷缭。如果Activity是暫停狀態(tài)饮亏,其中所有的Fragment都是暫停狀態(tài);如果Activity是stopped狀態(tài)阅爽,這個(gè)Activity中所有的Fragment都不能被啟動路幸;如果Activity被銷毀,那么它其中的所有Fragment都會被銷毀付翁。但是简肴,當(dāng)Activity在活動狀態(tài),可以獨(dú)立控制Fragment的狀態(tài)胆敞,比如加上或者移除Fragment着帽。
1. Fragment的幾種狀態(tài)
Fragment和activity一樣,也是有四種狀態(tài)
- 活動狀態(tài):Resumed
當(dāng)前Fragment位于前臺移层,用戶可見仍翰,可以獲得焦點(diǎn); - 暫停狀態(tài): Paused
另一個(gè)Activity處于前臺并擁有焦點(diǎn), 但是該Fragment所在的Activity仍然可見(前臺Activity局部透明或者沒有覆蓋整個(gè)屏幕)观话,不過不能獲得焦點(diǎn)予借; - 停止?fàn)顟B(tài):Stopped
要么是宿主Activity已經(jīng)被停止, 要么是Fragment從Activity被移除但被添加到回退棧中;停止?fàn)顟B(tài)的Fragment仍然活著(所有狀態(tài)和成員信息被系統(tǒng)保持著)频蛔。 然而, 它對用戶不再可見, 并且如果Activity被銷毀灵迫,它也會被銷毀; - 銷毀狀態(tài):Destroyed 只能等待被回收晦溪。
2.Fragment和Activity的對比
(1)活動和碎片之間的對比圖
(2)由上圖可以看出瀑粥,F(xiàn)ragment比Activity多了幾個(gè)額外的生命周期回調(diào)方法:
- onAttach() 當(dāng)碎片和活動建立關(guān)聯(lián)時(shí)調(diào)用。(獲得activity的傳遞的值)
- onCreateView() 為碎片創(chuàng)建視圖調(diào)用就是加載布局時(shí)三圆。
- onActivityCreated() 確保與碎片相關(guān)聯(lián)的活動一定已經(jīng)創(chuàng)建完畢的時(shí)候調(diào)用狞换。
- onDestroyView() 當(dāng)與碎片的視圖被移除的時(shí)候調(diào)用避咆。
- onDetach()當(dāng)碎片與活動解除關(guān)聯(lián)的時(shí)候調(diào)用。
三.如何使用Fragment
-
靜態(tài)使用
- 繼承Fragment修噪,重寫onCreateView決定Fragemnt的布局
- 在Activity中聲明此Fragment查库,就當(dāng)和普通的View一樣
關(guān)鍵代碼:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(layout, container, false); }
-
動態(tài)添加
1.創(chuàng)建待添加的碎片實(shí)例
2.獲取到FragmentManager,在活動中可以直接調(diào)用getFragmentManager()方法得到黄琼。
3.開啟一個(gè)事務(wù)樊销,通過調(diào)用beginTransaction()方法開啟
4.向容器內(nèi)添加碎片,一般使用replace()方法脏款,需要傳入容器的id和待添加的碎片實(shí)例围苫。
5.提交事務(wù),調(diào)用commit()(方法來完成撤师。
關(guān)鍵代碼:
FragmentManager fm = getFragmentManager();
// 開啟Fragment事務(wù)
FragmentTransaction transaction = fm.beginTransaction();
//Fragment的布局替代控件
transaction.replace(控件的id, 碎片實(shí)例);
// 事務(wù)提交
transaction.commit();
-
在碎片中模擬返回棧
通過點(diǎn)擊按鈕添加了一個(gè)碎片之后够吩,這時(shí)按下back鍵程序就會直接退出。如果這里我們想模仿類似返回棧的效果丈氓,按下back鍵可以返回到上一個(gè)碎片周循,在FragmentTransaction中提供了一個(gè)addToBackStack()方法,可以用于將一個(gè)事務(wù)添加到返回棧中
關(guān)鍵代碼:
transaction.addToBackStack(null);
注意: 在事務(wù)沒有提交之前添加代碼
四.Fragment的通信
Fragment和Activity之間的調(diào)用
-
活動中調(diào)用碎片的方法:
為了方便碎片與活動之間進(jìn)行通信万俗,F(xiàn)ragmentManager提供了一個(gè)類似于findViewById()的方法湾笛,專門從布局文件中獲取碎片的實(shí)例,代碼如下:
Fragment fragment=(Fragment)getFragmentManager()
.findFragmentById(R.id.fragment);
調(diào)用 FragmentManager 的 findFragmentById()方法闰歪,可以在活動中得到相應(yīng)碎片的實(shí)例嚎研,這樣就可以調(diào)用碎片的方法了。
-
碎片中調(diào)用活動的方法:
在每個(gè)碎片中都可以通過調(diào)用 getActivity()方法來得到和當(dāng)前碎片相關(guān)聯(lián) 的活動實(shí)例库倘,代碼如下:
MainActivity activity=(MainActivity)getActivity();
獲得活動實(shí)例后临扮,就可以在碎片中調(diào)用活動的方法。另外當(dāng)碎片中需要 使用 Context 對象時(shí)教翩,也可以使用 getActivity()方法杆勇,因?yàn)楂@取到的活動本身就是一個(gè)Context對象了。
Fragment和Activity之間的通信
- ** Handler方案**
public class MainActivity extends FragmentActivity{ //聲明一個(gè)Handler public Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
...相應(yīng)的處理代碼
}
}
...相應(yīng)的處理代碼
}
public class MainFragment extends Fragment{
//保存Activity傳遞的handler
private Handler mHandler;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//這個(gè)地方已經(jīng)產(chǎn)生了耦合饱亿,若還有其他的activity蚜退,這個(gè)地方就得修改
if(activity instance MainActivity){
mHandler = ((MainActivity)activity).mHandler;
}
}
...相應(yīng)的處理代碼
}
該方案存在的缺點(diǎn):
Fragment對具體的Activity存在耦合,不利于Fragment復(fù)用
不利于維護(hù)彪笼,若想刪除相應(yīng)的Activity钻注,F(xiàn)ragment也得改動
沒法獲取Activity的返回?cái)?shù)據(jù)
-
EventBus方案
主要功能是替代Intent,Handler,BroadCast在Fragment,Activity配猫,Service幅恋,線程之間傳遞消息.優(yōu)點(diǎn)是開銷小,代碼更優(yōu)雅泵肄。以及將發(fā)送者和接收者解耦捆交。
1识埋、下載EventBus的類庫源碼:https://github.com/greenrobot/EventBus
2、基本使用
(1)自定義一個(gè)類零渐,可以是空類,比如:
public class AnyEventType {
public AnyEventType(){}
}
(2)在要接收消息的頁面注冊:
eventBus.register(this);
(3)發(fā)送消息
eventBus.post(new AnyEventType event);
(4)接受消息的頁面實(shí)現(xiàn)(共有四個(gè)函數(shù)系忙,各功能不同诵盼,這是其中之一,可以選擇性的實(shí)現(xiàn)银还,這里先實(shí)現(xiàn)一個(gè)):
public void onEvent(AnyEventType event) {}
(5)解除注冊
eventBus.unregister(this);
注意:在EventBus中风宁,獲取實(shí)例的方法一般是采用EventBus.getInstance()來獲取默認(rèn)的EventBus實(shí)例,當(dāng)然你也可以new一個(gè)實(shí)例蛹疯。
- setArguments(Bundle bundle)方案:
public class ExampleFragment extends Fragment{
private String type;
public static ExampleFragment newInstance(String type) {
ExampleFragment myFragment = new ExampleFragment();
Bundle args = new Bundle();
args.putString("type", type);
//發(fā)送要傳遞的值
myFragment.setArguments(args);
return myFragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//接收數(shù)據(jù)
type=getArguments().getString("type");
...相應(yīng)的處理代碼
}
}
這種activity向fragment傳值方法是最簡單有效的戒财,而且在fragment異常重建的時(shí)候bundle將參數(shù)保存了下來
- ** 使用接口回調(diào)的方法通信(推薦)**
//MainActivity 實(shí)現(xiàn)MainFragment的接口
public class MainActivity extends FragmentActivity implements FragmentListener{
@override
public void toInterface (){ } ...其他處理代碼省略 }
public class MainFragment extends Fragment{
public FragmentListener mListener;
//MainFragment開放的接口
public static interface FragmentListener{
void toInterface (); }
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//對傳遞進(jìn)來的Activity進(jìn)行接口轉(zhuǎn)換
if(activity instance FragmentListener){
mListener = ((FragmentListener)activity);
} } ...其他處理代碼省略 }
這種方案應(yīng)該是既能達(dá)到復(fù)用,又能達(dá)到很好的可維護(hù)性捺弦,并且性能很好(推薦使用)