本文內(nèi)容:
-
設(shè)計(jì)哲學(xué)
-
創(chuàng)建fragment
-
添加用戶界面
-
向Activity添加fragment
-
管理fragment
-
執(zhí)行fragment事務(wù)
-
FragmentTransaction中的常用方法
-
Fragment的靜態(tài)加載
-
-
與Activity通信
-
創(chuàng)建對(duì)Activity的事件回調(diào)
-
向App Bar添加菜單
-
-
處理fragment生命周期
-
與 Activity 生命周期協(xié)調(diào)一致
-
Fragment 表示 Activity 中的一個(gè)行為或UI的一部分。您可以將多個(gè)fragment組合在一個(gè) Activity 中來構(gòu)建多窗格 UI沙合,以及在多個(gè) Activity 中重復(fù)使用某個(gè)Fragment。您可以將片段視為 Activity 的模塊化組成部分,它具有自己的生命周期昭躺,能接收自己的輸入事件缀台,并且在 Activity 運(yùn)行時(shí)可以被添加或移除(有點(diǎn)像您可以在不同 Activity 中重復(fù)使用的“子 Activity”)岳掐。
Fragment必須始終嵌入在 Activity 中凭疮,其生命周期直接受宿主 Activity 生命周期的影響。 例如岩四,當(dāng) Activity 暫停時(shí)哭尝,其中的所有Fragment也會(huì)暫停;當(dāng) Activity 被銷毀時(shí)剖煌,所有Fragment也會(huì)被銷毀。 不過逝淹,當(dāng) Activity 正在運(yùn)行時(shí)(處于onResume的生命周期狀態(tài))耕姊,您可以獨(dú)立操縱每個(gè)Fragment,如添加或移除它們栅葡。 當(dāng)您執(zhí)行此類fragment事務(wù)時(shí)茉兰,您也可以將fragment添加到由 Activity 管理的返回棧——Activity后退棧中的每一條記錄都是一條已發(fā)生的fragment事務(wù)欣簇。 返回棧讓用戶可以通過按返回按鈕撤消Fragment事務(wù)(后退)规脸。
當(dāng)您將fragment作為 Activity 布局的一部分添加時(shí),它存在于 Activity 視圖層次結(jié)構(gòu)的某個(gè) ViewGroup 內(nèi)部熊咽,并且Fragment會(huì)定義其自己的視圖布局莫鸭。您可以通過在 Activity 的布局文件中聲明Fragment,將其作為 <fragment> 元素插入您的 Activity 布局中横殴,或者通過將其添加到某個(gè)現(xiàn)有 ViewGroup被因,利用應(yīng)用代碼進(jìn)行插入。不過衫仑,fragment并非必須成為 Activity 布局的一部分梨与;您還可以將沒有自己 UI 的fragment用作 Activity 的不可見工作線程。
本文描述如何在開發(fā)您的應(yīng)用時(shí)使用fragment文狱,包括將fragment添加到 Activity 返回棧時(shí)如何保持其狀態(tài)粥鞋、如何與 Activity 及 Activity 中的其他fragment共享事件、如何為 Activity 的操作欄發(fā)揮作用等等瞄崇。
設(shè)計(jì)哲學(xué)
Android 在 Android 3.0(API 級(jí)別 11)中引入了fragment呻粹,主要是為了給大屏幕(如平板電腦)上更加動(dòng)態(tài)和靈活的 UI 設(shè)計(jì)提供支持到踏。由于平板電腦的屏幕比手機(jī)屏幕大得多,因此可用于組合和交換 UI 組件的空間更大尚猿。利用fragment實(shí)現(xiàn)此類設(shè)計(jì)時(shí)窝稿,您無需管理對(duì)視圖層次結(jié)構(gòu)的復(fù)雜更改。 通過將 Activity 布局分成fragment凿掂,您可以在運(yùn)行時(shí)修改 Activity 的外觀伴榔,并在由 Activity 管理的返回棧中保留這些更改。
例如庄萎,新聞應(yīng)用可以使用一個(gè)fragment在左側(cè)顯示文章列表踪少,使用另一個(gè)fragment在右側(cè)顯示文章—— 兩個(gè)fragment并排顯示在一個(gè) Activity 中,每個(gè)fragment都具有自己的一套生命周期回調(diào)方法糠涛,并各自處理自己的用戶輸入事件援奢。 因此,用戶不需要使用一個(gè) Activity 來選擇文章忍捡,然后使用另一個(gè) Activity 來閱讀文章集漾,而是可以在同一個(gè) Activity 內(nèi)選擇文章并進(jìn)行閱讀,如圖 1 中的平板電腦布局所示砸脊。
您應(yīng)該將每個(gè)fragment都設(shè)計(jì)為可重復(fù)使用的模塊化 Activity 組件具篇。也就是說,由于每個(gè)fragment都會(huì)通過各自的生命周期回調(diào)來定義其自己的布局和行為凌埂,您可以將一個(gè)fragment加入多個(gè) Activity驱显,因此,您應(yīng)該采用可復(fù)用式設(shè)計(jì)瞳抓,避免直接從某個(gè)fragment直接操縱另一個(gè)fragment埃疫。 這特別重要,因?yàn)槟K化fragment讓您可以通過更改fragment的組合方式來適應(yīng)不同的屏幕尺寸孩哑。 在設(shè)計(jì)可同時(shí)支持平板電腦和手機(jī)的應(yīng)用時(shí)栓霜,您可以在不同的布局配置中重復(fù)使用fragment,以根據(jù)可用的屏幕空間優(yōu)化用戶體驗(yàn)臭笆。 例如叙淌,在手機(jī)上,如果不能在同一 Activity 內(nèi)儲(chǔ)存多個(gè) fragment 愁铺,可能必須利用單獨(dú)fragment來實(shí)現(xiàn)單窗格 UI鹰霍。
創(chuàng)建fragment
要想創(chuàng)建fragment,您必須創(chuàng)建 Fragment 的子類(或已有的Fragment子類)茵乱。Fragment 類的代碼與 Activity 非常相似茂洒。它包含與 Activity 類似的回調(diào)方法,如 onCreate()瓶竭、onStart()督勺、onPause() 和 onStop()渠羞。實(shí)際上,如果您要將現(xiàn)有 Android 應(yīng)用轉(zhuǎn)換為使用fragment智哀,可能只需將代碼從 Activity 的回調(diào)方法移入fragment相應(yīng)的回調(diào)方法中次询。
通常,您至少應(yīng)實(shí)現(xiàn)以下生命周期方法:
onCreate()
系統(tǒng)會(huì)在創(chuàng)建 fragment 時(shí)調(diào)用此方法瓷叫。在實(shí)現(xiàn)內(nèi)應(yīng)該初始化想在ragment暫屯偷酰或停止后恢復(fù)時(shí)保留的必需fragment組件。
onCreateView()
系統(tǒng)會(huì)在fragment首次繪制其UI時(shí)調(diào)用此方法摹菠。 要想為您的fragment繪制 UI盒卸,您從此方法中返回的 View 必須是fragment布局的根視圖。如果fragment未提供 UI次氨,您可以返回 null蔽介。
onPause()
系統(tǒng)將此方法作為用戶離開fragment的第一個(gè)信號(hào)(但并不總是意味著此fragment會(huì)被銷毀)進(jìn)行調(diào)用。 您通常應(yīng)該在此方法內(nèi)確認(rèn)在當(dāng)前用戶會(huì)話結(jié)束后仍然有效的任何更改(因?yàn)橛脩艨赡懿粫?huì)返回)煮寡。
大多數(shù)應(yīng)用都應(yīng)該至少為每個(gè)fragment實(shí)現(xiàn)這三個(gè)方法虹蓄,但您還應(yīng)該使用幾種其他回調(diào)方法來處理fragment生命周期的各個(gè)階段。
您可能還想擴(kuò)展幾個(gè)子類洲押,而不是 Fragment 基類:
DialogFragment
顯示浮動(dòng)對(duì)話框武花。使用此類創(chuàng)建對(duì)話框可有效地替代使用 Activity 類中的對(duì)話框幫助程序方法,因?yàn)槟梢詫⑵螌?duì)話框納入由 Activity 管理的片段返回棧杈帐,從而使用戶能夠返回清除的片段。
ListFragment
顯示由適配器(如 SimpleCursorAdapter)管理的一系列項(xiàng)目专钉,類似于 ListActivity挑童。它提供了幾種管理列表視圖的方法,如用于處理點(diǎn)擊事件的 onListItemClick() 回調(diào)跃须。
PreferenceFragment
以列表形式顯示 Preference 對(duì)象的層次結(jié)構(gòu)站叼,類似于 PreferenceActivity。這在為您的應(yīng)用創(chuàng)建“設(shè)置” Activity 時(shí)很有用處菇民。
添加用戶界面
Fragment 通常用作 Activity UI的一部分尽楔,將其自己的布局融入 Activity第练。要想為fragment提供布局阔馋,您必須實(shí)現(xiàn) onCreateView() 回調(diào)方法,Android 系統(tǒng)會(huì)在需要繪制其布局時(shí)調(diào)用該方法娇掏。您對(duì)此方法的實(shí)現(xiàn)返回的 View 必須是片段布局的根視圖呕寝。
注:如果fragment是 ListFragment 的子類,則默認(rèn)實(shí)現(xiàn)會(huì)從onCreateView()返回一個(gè) ListView婴梧,因此無需實(shí)現(xiàn)它下梢。
要想從 onCreateView() 返回布局客蹋,您可以通過 XML 中定義的布局資源來擴(kuò)展布局。為幫助您執(zhí)行此操作孽江,onCreateView() 提供了一個(gè) LayoutInflater 對(duì)象讶坯。
例如,以下這個(gè) Fragment 子類從 example_fragment.xml 文件加載布局:
public static class ExampleFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, container, false);
}
}
傳遞至 onCreateView() 的 container 參數(shù)是fragment布局將插入到的父 ViewGroup(來自 Activity 的布局)岗屏。savedInstanceState 參數(shù)是在恢復(fù)片段時(shí)辆琅,提供上一片段實(shí)例相關(guān)數(shù)據(jù)的 Bundle。
inflate() 方法帶有三個(gè)參數(shù):
- 您想要擴(kuò)展的布局的資源 ID担汤;
- 將作為擴(kuò)展布局父項(xiàng)的 ViewGroup涎跨。傳遞 container 對(duì)系統(tǒng)向擴(kuò)展布局的根視圖(由其所屬的父視圖指定)應(yīng)用布局參數(shù)具有重要意義;
- 指示是否應(yīng)該在擴(kuò)展期間將擴(kuò)展布局附加至 ViewGroup(第二個(gè)參數(shù))的布爾值崭歧。(在本例中隅很,其值為 false,因?yàn)橄到y(tǒng)已經(jīng)將擴(kuò)展布局插入 container —— 傳遞 true 值會(huì)在最終布局中創(chuàng)建一個(gè)多余的視圖組率碾。)
現(xiàn)在叔营,您已經(jīng)了解了如何創(chuàng)建提供布局的fragment。接下來所宰,您需要將該fragment添加到您的 Activity 中绒尊。
向Activity添加fragment
通常,fragment向宿主 Activity 貢獻(xiàn)一部分 UI仔粥,作為 Activity 總體視圖層次結(jié)構(gòu)的一部分嵌入到 Activity 中婴谱。可以通過兩種方式向 Activity 布局添加fragment:
-
在 Activity 的布局文件內(nèi)聲明fragment
在本例中躯泰,您可以將fragment當(dāng)作視圖來為其指定布局屬性谭羔。 例如,以下是一個(gè)具有兩個(gè)fragment的 Activity 的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="com.example.news.ArticleListFragment"
android:id="@+id/list"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="com.example.news.ArticleReaderFragment"
android:id="@+id/viewer"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
<fragment> 中的 android:name 屬性指定要在布局中實(shí)例化的 Fragment 類麦向。
-
或者通過編程方式將 fragment 添加到某個(gè)現(xiàn)有 ViewGroup
您可以在 Activity 運(yùn)行期間隨時(shí)將 fragment 添加到 Activity 布局中瘟裸。您只需指定要將 fragment 放入哪個(gè) ViewGroup。
要想在您的 Activity 中執(zhí)行 fragment (如添加诵竭、移除或替換 fragment )话告,您必須使用 FragmentTransaction 中的 API。您可以像下面這樣從 Activity 獲取一個(gè) FragmentTransaction 實(shí)例:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
然后卵慰,您可以使用 add() 方法添加一個(gè) fragment 沙郭,指定要添加的 fragment 以及將其插入哪個(gè)視圖。例如:
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
傳遞到 add() 的第一個(gè)參數(shù)是 ViewGroup呵燕,即應(yīng)該放置 fragment 的位置棠绘,由資源 ID 指定,第二個(gè)參數(shù)是要添加的 fragment 。
一旦您通過 FragmentTransaction 做出了更改氧苍,就必須調(diào)用 commit() 以使更改生效夜矗。
添加沒有 UI 的 fragment
例展示了如何向您的 Activity 添加 fragment 以提供 UI。不過让虐,您還可以使用 fragment 為 Activity 提供后臺(tái)行為紊撕,而不顯示額外 UI。
要想添加沒有 UI 的 fragment 赡突,請(qǐng)使用 add(Fragment, String) 從 Activity 添加 fragment (為 fragment 提供一個(gè)唯一的字符串“標(biāo)記”对扶,而不是視圖 ID)。 這會(huì)添加 fragment 惭缰,但由于它并不與 Activity 布局中的視圖關(guān)聯(lián)浪南,因此不會(huì)收到對(duì) onCreateView() 的調(diào)用。因此漱受,您不需要實(shí)現(xiàn)該方法络凿。
并非只能為非 UI 片段提供字符串標(biāo)記 — 您也可以為具有 UI 的片段提供字符串標(biāo)記 — 但如果片段沒有 UI,則字符串標(biāo)記將是標(biāo)識(shí)它的唯一方式昂羡。如果您想稍后從 Activity 中獲取fragment絮记,則需要使用 findFragmentByTag()。
如需查看將沒有 UI 的fragment用作后臺(tái)工作線程的示例 Activity虐先,請(qǐng)參閱 FragmentRetainInstance.java 示例怨愤,該示例包括在 SDK 示例(通過 Android SDK 管理器提供)中,以
<sdk_root>/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java 形式位于您的系統(tǒng)中蛹批。
管理fragment
要想管理您的 Activity 中的 fragment 撰洗,您需要使用 FragmentManager。要想獲取它腐芍,請(qǐng)從您的 Activity 調(diào)用 getFragmentManager()了赵。
您可以使用 FragmentManager 執(zhí)行的操作包括:
- 通過 findFragmentById()(對(duì)于在 Activity 布局中提供 UI 的片段)或 findFragmentByTag()(對(duì)于提供或不提供 UI 的片段)獲取 Activity 中存在的 fragment 。
- 通過 popBackStack()(模擬用戶發(fā)出的返回命令)將片段從返回棧中彈出甸赃。
- 通過 addOnBackStackChangedListener() 注冊(cè)一個(gè)偵聽返回棧變化的偵聽器。
如需了解有關(guān)這些方法以及其他方法的詳細(xì)信息冗酿,請(qǐng)參閱 FragmentManager 類文檔埠对。
執(zhí)行fragment事務(wù)
提交給 Activity 的每組更改都稱為事務(wù),您可以使用 FragmentTransaction 中的 API 來執(zhí)行一項(xiàng)事務(wù)裁替。您也可以將每個(gè)事務(wù)保存到由 Activity 管理的返回棧內(nèi)项玛,從而讓用戶能夠回退 fragment (類似于回退 Activity)。
從 FragmentManager 獲取一個(gè) FragmentTransaction 實(shí)例:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
每個(gè)事務(wù)都是您想要同時(shí)執(zhí)行的一組更改弱判。您可以使用 add()襟沮、remove() 和 replace() 等方法為給定事務(wù)設(shè)置您想要執(zhí)行的所有更改。然后,要想將事務(wù)應(yīng)用到 Activity开伏,您必須調(diào)用 commit()膀跌。
不過,在您調(diào)用 commit() 之前固灵,您可能想調(diào)用 addToBackStack()捅伤,以將事務(wù)添加到片段事務(wù)返回棧。 該返回棧由 Activity 管理巫玻,允許用戶通過按返回按鈕返回上一片段狀態(tài)丛忆。
例如,以下示例說明了如何將一個(gè) fragment 替換成另一個(gè) fragment 仍秤,以及如何在返回棧中保留先前狀態(tài):
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
在上例中熄诡,newFragment 會(huì)替換目前在 R.id.fragment_container ID 所標(biāo)識(shí)的布局容器中的任何 fragment (如有)。通過調(diào)用 addToBackStack() 可將替換事務(wù)保存到返回棧诗力,以便用戶能夠通過按返回按鈕撤消事務(wù)并回退到上一 fragment 凰浮。
如果您向事務(wù)添加了多個(gè)更改(如又一個(gè) add() 或 remove()),并且調(diào)用了 addToBackStack()姜骡,則在調(diào)用 commit() 前應(yīng)用的所有更改都將作為單一事務(wù)添加到返回棧导坟,并且返回按鈕會(huì)將它們一并撤消。
向 FragmentTransaction 添加更改的順序無關(guān)緊要圈澈,不過:
- 您必須最后調(diào)用 commit()
- 如果您要向同一容器添加多個(gè) fragment 惫周,則您添加 fragment 的順序?qū)Q定它們?cè)谝晥D層次結(jié)構(gòu)中的出現(xiàn)順序
如果您沒有在執(zhí)行移除 fragment 的事務(wù)時(shí)調(diào)用 addToBackStack(),則事務(wù)提交時(shí)該 fragment 會(huì)被銷毀康栈,用戶將無法回退到該 fragment 递递。 否則(即調(diào)用了addToBackStack()),則系統(tǒng)會(huì)停止該調(diào)用 addToBackStack()啥么,并在用戶回退時(shí)將其恢復(fù)登舞。
提示:對(duì)于每個(gè) fragment 事務(wù),您都可以通過在提交前調(diào)用 setTransition() 來應(yīng)用過渡動(dòng)畫悬荣。
調(diào)用 commit() 不會(huì)立即執(zhí)行事務(wù)菠秒,而是在 Activity 的 UI 線程(“主”線程)可以執(zhí)行該操作時(shí)再安排其在線程上運(yùn)行。不過氯迂,如有必要践叠,您也可以從 UI 線程調(diào)用 executePendingTransactions() 以立即執(zhí)行 commit() 提交的事務(wù)。通常不必這樣做嚼蚀,除非其他線程中的作業(yè)依賴該事務(wù)禁灼。
注意:您只能在 Activity 保存其狀態(tài)(用戶離開 Activity)之前使用 commit() 提交事務(wù)。如果您試圖在該時(shí)間點(diǎn)后提交轿曙,則會(huì)引發(fā)異常弄捕。 這是因?yàn)槿缧杌謴?fù) Activity僻孝,則提交后的狀態(tài)可能會(huì)丟失。 對(duì)于丟失提交無關(guān)緊要的情況守谓,請(qǐng)使用 commitAllowingStateLoss()穿铆。
FragmentTransaction中的常用方法:
- add():往Activity中添加一個(gè)Fragment。
- remove():從Activity中移除一個(gè)Fragment分飞,如果被移除的Fragment沒有添加到回退棧悴务,這個(gè)Fragment實(shí)例將會(huì)被銷毀。
- replace():使用另一個(gè)Fragment替換當(dāng)前的譬猫,實(shí)際上就是remove()然后add()的合體讯檐。
- hide():隱藏當(dāng)前的Fragment,僅僅是設(shè)為不可見染服,并不會(huì)銷毀别洪。
- show():顯示之前隱藏的Fragment
- detach():將此Fragment從Activity中分離,會(huì)銷毀其布局柳刮,但不會(huì)銷毀該實(shí)例挖垛。
- attach():將從Activity中分離的Fragment,重新關(guān)聯(lián)到該Activity秉颗,重新創(chuàng)建其視圖層次痢毒。
- commit():提交一個(gè)事務(wù)。
Fragment的靜態(tài)加載
以上使用是動(dòng)態(tài)加載fragment蚕甥,還可以如下靜態(tài)加載fragment哪替。
靜態(tài)加載Fragment分三步:
- 創(chuàng)建一個(gè)Layout,作為要靜態(tài)加載的Fragment的布局菇怀。
- 創(chuàng)建一個(gè)類繼承Fragment凭舶,然后重寫里面的onCreateView方法,View對(duì)象為剛剛創(chuàng)建的Layout爱沟。
- 在Layout布局文件中聲明fragment帅霜,android:name屬性里是我們上面創(chuàng)建的類,另外呼伸,fragment必須用id或tag作為唯一標(biāo)識(shí)身冀。
與 Activity 通信
盡管 Fragment 是作為獨(dú)立于 Activity 的對(duì)象實(shí)現(xiàn),并且可在多個(gè) Activity 內(nèi)使用括享,但fragment的給定實(shí)例會(huì)直接綁定到包含它的 Activity闽铐。
具體地說,fragment可以通過 getActivity() 訪問 Activity 實(shí)例奶浦,并輕松地執(zhí)行在 Activity 布局中查找視圖等任務(wù)。
View listView = getActivity().findViewById(R.id.list);
同樣地踢星,您的 Activity 也可以使用 findFragmentById() 或 findFragmentByTag()澳叉,通過從 FragmentManager 獲取對(duì) Fragment 的引用來調(diào)用片段中的方法。例如:
ExampleFragment fragment = (ExampleFragment)
getFragmentManager().findFragmentById(R.id.example_fragment);
創(chuàng)建對(duì)Activity的事件回調(diào)
在某些情況下,您可能需要通過 fragment 與 Activity 共享事件成洗。執(zhí)行此操作的一個(gè)好方法是五督,在 fragment 內(nèi)定義一個(gè)回調(diào)接口,并要求宿主 Activity 實(shí)現(xiàn)它瓶殃。 當(dāng) Activity 通過該接口收到回調(diào)時(shí)充包,可以根據(jù)需要與布局中的其他 fragment 共享這些信息。
例如遥椿,如果一個(gè)新聞應(yīng)用的 Activity 有兩個(gè) fragment —— 一個(gè)用于顯示文章列表( fragment A)基矮,另一個(gè)用于顯示文章( fragment B),那么 fragment A 必須在列表項(xiàng)被選定后告知 Activity冠场,以便它告知 fragment B 顯示該文章家浇。 在本例中,OnArticleSelectedListener 接口在 fragment A 內(nèi)聲明:
public static class FragmentA extends ListFragment {
...
// Container Activity must implement this interface
public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
...
}
如果 Activity 未實(shí)現(xiàn)接口碴裙,則 fragment 會(huì)引發(fā) ClassCastException钢悲。實(shí)現(xiàn)時(shí),mListener 成員會(huì)保留對(duì) Activity 的 OnArticleSelectedListener 實(shí)現(xiàn)的引用舔株,以便 fragment A 可以通過調(diào)用 OnArticleSelectedListener 接口定義的方法與 Activity 共享事件莺琳。例如,如果 fragment A 是 ListFragment 的一個(gè)擴(kuò)展载慈,則用戶每次點(diǎn)擊列表項(xiàng)時(shí)惭等,系統(tǒng)都會(huì)調(diào)用 fragment 中的 onListItemClick(),然后該方法會(huì)調(diào)用 onArticleSelected() 以與 Activity 共享事件:
public static class FragmentA extends ListFragment {
OnArticleSelectedListener mListener;
...
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Append the clicked item's row ID with the content provider Uri
Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
// Send the event and Uri to the host activity
mListener.onArticleSelected(noteUri);
}
...
}
傳遞到 onListItemClick() 的 id 參數(shù)是被點(diǎn)擊項(xiàng)的行 ID娃肿,即 Activity(或其他fragment)用來從應(yīng)用的 ContentProvider 獲取文章的 ID咕缎。
Fragment之間使用Bundle傳遞數(shù)據(jù)
FragmentOne:在用戶點(diǎn)擊按鈕時(shí),將fragment2添加到當(dāng)前頁面顯示出來料扰,并傳遞一個(gè)Bundle對(duì)象凭豪。
@Override
public void onClick(View v)
{
//FragmentTwo是從FragmentOne即將跳轉(zhuǎn)到的第二個(gè)Fragment
FragmentTwo fTwo = new FragmentTwo();
//利用Bundle傳遞“key”中保存的參數(shù)Path中數(shù)據(jù)
Bundle bundle = new Bundle();
bundle.putString("key", Path);
fTwo.setArguments(bundle);
getFragmentManager().beginTransaction()
.replace(R.id.id_content, fTwo, "TWO");
.addToBackStack(null);
.commit();
}
FragmentTwo:在FragmentTwo中獲取傳遞的參數(shù):
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.right, null);
TextView textView = (TextView) view.findViewById(R.id.textView1);
Bundle bundle = getArguments();
if (bundle != null) {
String item = bundle.getString("key");
textView.setText(item);
}
return view;
}
向App Bar添加菜單
您的fragment可以通過實(shí)現(xiàn) onCreateOptionsMenu() 向 Activity 的選項(xiàng)菜單(并因此向應(yīng)用欄)貢獻(xiàn)菜單項(xiàng)。不過晒杈,為了使此方法能夠收到調(diào)用嫂伞,您必須在 onCreate() 期間調(diào)用 setHasOptionsMenu(),以指示片段想要向選項(xiàng)菜單添加菜單項(xiàng)(否則拯钻,fragment將不會(huì)收到對(duì) onCreateOptionsMenu() 的調(diào)用)帖努。
您之后從fragment添加到選項(xiàng)菜單的任何菜單項(xiàng)都將追加到現(xiàn)有菜單項(xiàng)之后。 選定菜單項(xiàng)時(shí)粪般,fragment還會(huì)收到對(duì) onOptionsItemSelected() 的回調(diào)拼余。
您還可以通過調(diào)用 registerForContextMenu(),在fragment布局中注冊(cè)一個(gè)視圖來提供浮動(dòng)上下文菜單亩歹。用戶打開上下文菜單時(shí)匙监,fragment會(huì)收到對(duì) onCreateContextMenu()}的調(diào)用凡橱。當(dāng)用戶選擇某個(gè)菜單項(xiàng)時(shí),fragment會(huì)收到對(duì) onContextItemSelected() 的調(diào)用亭姥。
處理fragment生命周期
管理fragment生命周期與管理 Activity 生命周期很相似稼钩。和 Activity 一樣,fragment也以三種狀態(tài)存在:
- Resume
fragment在運(yùn)行中的 Activity 中可見达罗。 - Pause
另一個(gè) Activity 位于前臺(tái)并具有焦點(diǎn)坝撑,但此fragment所在的 Activity 仍然可見(前臺(tái) Activity 部分透明,或未覆蓋整個(gè)屏幕)粮揉。 - Stop
fragment不可見巡李。宿主 Activity 已停止,或fragment已從 Activity 中移除滔蝉,但已添加到返回棧击儡。 停止fragment仍然處于存活狀態(tài)(系統(tǒng)會(huì)保留所有狀態(tài)和成員信息)。 不過蝠引,它對(duì)用戶不再可見阳谍,如果 Activity 被終止,它也會(huì)被終止螃概。
同樣與 Activity 一樣矫夯,假使 Activity 的進(jìn)程被終止,而您需要在重建 Activity 時(shí)恢復(fù)片段狀態(tài)吊洼,您也可以使用 Bundle 保留片段的狀態(tài)训貌。您可以在fragment的 onSaveInstanceState() 回調(diào)期間保存狀態(tài),并可在 onCreate()冒窍、onCreateView() 或 onActivityCreated() 期間恢復(fù)狀態(tài)递沪。
Activity 生命周期與fragment生命周期之間的最顯著差異在于它們?cè)谄涓髯苑祷貤V械拇鎯?chǔ)方式。 默認(rèn)情況下综液,Activity 停止時(shí)會(huì)被放入由系統(tǒng)管理的 Activity 返回棧(以便用戶通過返回按鈕回退到 Activity款慨,任務(wù)和返回棧對(duì)此做了闡述)。然而谬莹,僅當(dāng)您在移除fragment的事務(wù)執(zhí)行期間通過調(diào)用 addToBackStack() 顯式請(qǐng)求保存實(shí)例時(shí)檩奠,系統(tǒng)才會(huì)將fragment放入由宿主 Activity 管理的返回棧。
在其他方面附帽,管理fragment生命周期與管理 Activity 生命周期非常相似埠戳。 因此,管理 Activity 生命周期的做法同樣適用于fragment蕉扮。 但您還需要了解 Activity 的生命周期對(duì)fragment生命周期的影響整胃。
注意:如需 Fragment 內(nèi)的某個(gè) Context 對(duì)象,可以調(diào)用 getActivity()喳钟。但要注意爪模,請(qǐng)僅在fragment附加到 Activity 時(shí)調(diào)用 getActivity()欠啤。如果fragment尚未附加,或在其生命周期結(jié)束期間分離屋灌,則 getActivity() 將返回 null。
與 Activity 生命周期協(xié)調(diào)一致
fragment所在的 Activity 的生命周期會(huì)直接影響fragment的生命周期应狱,其表現(xiàn)為共郭,Activity 的每次生命周期回調(diào)都會(huì)引發(fā)每個(gè)fragment的類似回調(diào)。 例如疾呻,當(dāng) Activity 收到 onPause() 時(shí)除嘹,Activity 中的每個(gè)fragment也會(huì)收到 onPause()。
不過岸蜗,fragment還有幾個(gè)額外的生命周期回調(diào)尉咕,用于處理與 Activity 的唯一交互,以執(zhí)行構(gòu)建和銷毀片段 UI 等操作璃岳。 這些額外的回調(diào)方法是:
- onAttach()
在fragment已與 Activity 關(guān)聯(lián)時(shí)調(diào)用(Activity 傳遞到此方法內(nèi))年缎。 - onCreateView()
調(diào)用它可創(chuàng)建與fragment關(guān)聯(lián)的視圖層次結(jié)構(gòu)。 - onActivityCreated()
在 Activity 的 onCreate() 方法已返回時(shí)調(diào)用铃慷。 - onDestroyView()
在移除與fragment關(guān)聯(lián)的視圖層次結(jié)構(gòu)時(shí)調(diào)用单芜。 - onDetach()
在取消fragment與 Activity 的關(guān)聯(lián)時(shí)調(diào)用。
圖 3 圖示說明了受其宿主 Activity 影響的fragment生命周期犁柜。在該圖中洲鸠,您可以看到 Activity 的每個(gè)連續(xù)狀態(tài)如何決定fragment可以收到的回調(diào)方法。 例如馋缅,當(dāng) Activity 收到其 onCreate() 回調(diào)時(shí)扒腕,Activity 中的fragment只會(huì)收到 onActivityCreated() 回調(diào)。
一旦 Activity 達(dá)到resumed狀態(tài)萤悴,您就可以隨意向 Activity 添加fragment和移除其中的fragment瘾腰。 因此,只有當(dāng) Activity 處于resumed狀態(tài)時(shí)稚疹,fragment的生命周期才能獨(dú)立變化居灯。
不過,當(dāng) Activity 離開resumed狀態(tài)時(shí)内狗,fragment會(huì)在 Activity 的推動(dòng)下再次經(jīng)歷其生命周期怪嫌。
Fragment的向下兼容
- 當(dāng)對(duì)Fragment引用包的時(shí)候,會(huì)有兩個(gè)選項(xiàng)柳沙,android.app.Fragment和android.support.v4.app.Fragment岩灭,其中android.support.v4.app.Fragment就是為了兼容低版本(當(dāng)API Version 低于11時(shí))而考慮的。
- 使用android.support.v4.app.Fragment時(shí)赂鲤,Activity需要繼承FragmentActivity噪径,如果Activity繼承了AppCompatActivity就不用了柱恤,AppCompatActivity已經(jīng)繼承了FragmentActivity。
順便推薦簡(jiǎn)書上關(guān)于Fragment的一個(gè)系列:
Fragment完全解析系列一
Fragment完全解析系列二
Fragment之我的解決方案