在各種Android項(xiàng)目中,我們不可避免要使用到Fragment,但很多地方其實(shí)我們只是習(xí)慣性或copy代碼來(lái)使用,很多地方并沒(méi)有深入去了解,今天就通過(guò)這篇文章整理和回顧一下關(guān)于Fragment的種種。而在自己總結(jié)的過(guò)程中,我也發(fā)現(xiàn)自己在很多細(xì)節(jié)方面有一些知識(shí)上的不足和理解上的錯(cuò)誤,這也會(huì)讓我對(duì)整理的知識(shí)掌握得更全面。
Fragment的生命周期
生命周期自然是首先要弄清楚的,先上我們最經(jīng)常見(jiàn)到的Android官網(wǎng)關(guān)于Fragment的生命周期圖:

關(guān)于Fragment最基本的生命周期大家應(yīng)該都很熟悉,但有幾點(diǎn)需要詳細(xì)說(shuō)一下:
1. 關(guān)于Fragment的回收
- 仔細(xì)看上圖中的英文提示,會(huì)發(fā)現(xiàn)在Fragment的onDestroyView()方法之后有兩個(gè)剪頭指向,一個(gè)是直接去執(zhí)行onDestroy()方法,另一個(gè)是重新去走onCreateView()方法。造成這兩種情況的原因是因?yàn)镕ragmentManager對(duì)Fragment的不同管理方式。用一個(gè)我們最常用到的場(chǎng)景來(lái)說(shuō)明:
ViewPager搭配Fragment來(lái)使用時(shí),系統(tǒng)為我們提供了兩個(gè)適用的adapter:FragmentPagerAdapter和FragmentStatePagerAdapter,這兩個(gè)adapter最大的不同之處就是對(duì)Fragment的回收管理。在FragmentPagerAdapter的instantiateItem()和destroyItem方法中,對(duì)多個(gè)Fragment展示和回收的處理主要是通過(guò)FragmentTransaction的attach和detach方法來(lái)處理;而在FragmentStatePagerAdapter中,是通過(guò)通過(guò)FragmentTransaction的add和remove方法來(lái)處理。后者的Fragment在不可見(jiàn)時(shí)執(zhí)行完onDestroyView()后直接去執(zhí)行onDestroy()把當(dāng)前Fragment完全銷(xiāo)毀;而前者的Fragment在執(zhí)行完onDestroyView()后則不再執(zhí)行,而會(huì)在下一次這個(gè)Fragment重新可見(jiàn)時(shí),去通過(guò)onCreateView()來(lái)重新創(chuàng)建視圖,也就是說(shuō)Fragment并沒(méi)有被完全銷(xiāo)毀而只是被回收了View而已。
這一點(diǎn)在后面關(guān)于ViewPager使用場(chǎng)景相關(guān)的文章中我會(huì)再在詳細(xì)說(shuō)到。
2. Fragment和Activity生命周期的聯(lián)系
- 自然先看官方給出的聯(lián)系圖:

上圖雖然很清晰,但Activity和Fragment生命周期每個(gè)階段更細(xì)致的順序并看不出來(lái)。這點(diǎn)只有通過(guò)手動(dòng)跑一下測(cè)試代碼來(lái)看了


上面是我通過(guò)一個(gè)簡(jiǎn)單的測(cè)試代碼來(lái)打印的生命周期log,啟動(dòng)MainActivity,TestFragment顯示MainActivity中。值得注意的,除了onResume方法是Activity先執(zhí)行而Fragment后執(zhí)行外,其他階段的生命周期方法都是Fragment先執(zhí)行之后,Activity再執(zhí)行的。
3. Fragment的onSaveInstanceState方法**
onSaveInstanceState的調(diào)用時(shí)機(jī)Fragment通Activity是一樣的, 都是在當(dāng)前界面進(jìn)入可被系統(tǒng)回收狀態(tài)時(shí)就會(huì)被調(diào)用。看一下啟動(dòng)MainActivity后按home鍵回到桌面時(shí),onSaveInstanceState的調(diào)用情況:

所以,當(dāng)我們需要保存Fragment相關(guān)的狀態(tài)時(shí),可以通過(guò)這個(gè)方法。需要注意的一點(diǎn)是,F(xiàn)ragment本身并沒(méi)有通Activity一致的onRestoreInstanceState方法,所以如官方文檔所說(shuō)
您可以在Fragment的onSaveInstanceState()回調(diào)期間保存狀態(tài),并可在onCreate()、onCreateView() 或 onActivityCreated() 期間恢復(fù)狀態(tài)。
4. 關(guān)于Fragment的setUserVisibleHint方法**
這個(gè)方法嚴(yán)格來(lái)說(shuō)不屬于Fragment生命周期的范疇,但有人把它比作是Fragment真正的onResume和onStop方法,主要是因?yàn)榕浜线@個(gè)方法可以在使用ViewPager+Fragment時(shí)實(shí)現(xiàn)懶加載,因?yàn)镕ragment的onResume方法與Activity的onResume方法是一致的,所以無(wú)法通過(guò)onResume方法來(lái)判斷Fragment是否可見(jiàn),反而可以通過(guò)setUserVisibleHint來(lái)準(zhǔn)確判斷(關(guān)于ViewPager的懶加載后續(xù)的文章中也會(huì)詳細(xì)講到),當(dāng)然如果項(xiàng)目中有用到友盟統(tǒng)計(jì),也可以通過(guò)該方法更加準(zhǔn)確的上報(bào)Fragment的相關(guān)數(shù)據(jù)。
說(shuō)setUserVisibleHint不屬于Fragment生命周期的范疇主要是因?yàn)樗⒉粫?huì)被系統(tǒng)主動(dòng)來(lái)回調(diào)。原先我也認(rèn)為只要Fragment的可見(jiàn)性發(fā)生變化就會(huì)回調(diào)它,自己用代碼打印時(shí)才發(fā)現(xiàn)并非如此。如果Activity中有一個(gè)Fragment,無(wú)論是進(jìn)入另一個(gè)Activity,還是按home鍵回到桌面,setUserVisibleHint方法都不會(huì)調(diào)用。Google一番外加看源碼,才明白原來(lái)這個(gè)方法是需要我們主動(dòng)調(diào)用來(lái)告知系統(tǒng)當(dāng)前Fragment的可見(jiàn)性,源碼注釋這樣說(shuō):
/* Set a hint to the system about whether this fragment's UI is currently visible
* to the user. This hint defaults to true and is persistent across fragment instance
* state save and restore.
*
* <p>An app may set this to false to indicate that the fragment's UI is
* scrolled out of visibility or is otherwise not directly visible to the user.
* This may be used by the system to prioritize operations such as fragment lifecycle updates
* or loader ordering behavior.</p>
*
* @param isVisibleToUser true if this fragment's UI is currently visible to the user (default),
* false if it is not.
*/
public void setUserVisibleHint(boolean isVisibleToUser) {
if (!mUserVisibleHint && isVisibleToUser && mState < STARTED) {
mFragmentManager.performPendingDeferredStart(this);
}
mUserVisibleHint = isVisibleToUser;
mDeferStart = !isVisibleToUser;
}
系統(tǒng)為我們提供的配合ViewPager+Fragment的適配器FragmentPagerAdapter和FragmentStatePagerAdapter中,也是在ViewPager的fragment item進(jìn)行初始化和切換時(shí)主動(dòng)調(diào)用了該方法。
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
// 此處主動(dòng)調(diào)用了setUserVisibleHint方法
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
5. 其他
Activity 生命周期與Fragment生命周期之間的最顯著差異在于它們?cè)谄涓髯苑祷貤V械拇鎯?chǔ)方式。 默認(rèn)情況下,Activity 停止時(shí)會(huì)被放入由系統(tǒng)管理的 Activity 返回棧(以便用戶(hù)通過(guò)“返回”按鈕回退到Activity,任務(wù)和返回棧對(duì)此做了闡述)。不過(guò),僅當(dāng)您在刪除Fragment的事務(wù)執(zhí)行期間通過(guò)調(diào)用 addToBackStack() 顯式請(qǐng)求保存實(shí)例時(shí),系統(tǒng)才會(huì)將Fragment放入由宿主 Activity 管理的返回棧。
在其他方面,管理Fragment生命周期與管理 Activity 生命周期非常相似。 因此,管理 Activity 生命周期的做法同樣適用于Fragment。
注意:如需 Fragment 內(nèi)的某個(gè) Context 對(duì)象,可以調(diào)用 getActivity()。但要注意,請(qǐng)僅在Fragment附加到 Activity 時(shí)調(diào)用 getActivity()。如果Fragment尚未附加,或在其生命周期結(jié)束期間分離,則 getActivity() 將返回 null。
Fragment的使用
Fragment必須始終嵌套在A(yíng)ctivity中,其生命周期直接受宿主 Activity 生命周期的影響。 例如,當(dāng) Activity 暫停時(shí),其中的所有的Fragment也會(huì)暫停;當(dāng) Activity 被銷(xiāo)毀時(shí),所有的Fragment也會(huì)被銷(xiāo)毀。 不過(guò),當(dāng) Activity 正在運(yùn)行(處于onResume狀態(tài))時(shí),您可以獨(dú)立操縱每個(gè)Fragment,如添加或移除它們。 當(dāng)您執(zhí)行此類(lèi)Fragment事務(wù)時(shí),您也可以將其添加到由 Activity 管理的返回?!狝ctivity 中的每個(gè)返回棧條目都是一條已發(fā)生Fragment事務(wù)的記錄。 返回棧讓用戶(hù)可以通過(guò)按“返回”按鈕撤消Fragment事務(wù)(后退)。
當(dāng)您將Fragment作為 Activity 布局的一部分添加時(shí),它存在于 Activity 視圖層次結(jié)構(gòu)的某個(gè) ViewGroup 內(nèi)部,并且Fragment會(huì)定義其自己的視圖布局。您可以通過(guò)在 Activity 的布局文件中聲明Fragment,將其作為 <fragment>
元素插入您的 Activity 布局中,或者通過(guò)將其添加到某個(gè)現(xiàn)有 ViewGroup,利用應(yīng)用代碼進(jìn)行插入。不過(guò),F(xiàn)ragment并非必須成為 Activity 布局的一部分;您還可以將沒(méi)有自己 UI 的Fragment用作 Activity 的不可見(jiàn)工作線(xiàn)程。
1. 創(chuàng)建Fragment的視圖
要想為Fragment提供布局,就必須實(shí)現(xiàn)onCreateView()回調(diào)方法,Android系統(tǒng)會(huì)在Fragment需要繪制其布局時(shí)調(diào)用該方法。對(duì)此方法的實(shí)現(xiàn)返回的View必須是片段布局的根視圖。
要想從onCreateView()返回布局,可以通過(guò)xml中定義的布局資源來(lái)擴(kuò)展布局。為此,onCreateView()專(zhuān)門(mén)提供了一個(gè)LayoutInflater對(duì)象。
例如,以下這個(gè)Fragment子類(lèi)從 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(來(lái)自Activity的布局)。savedInstanceState是在恢復(fù)Fragment時(shí),提供上一Fragment實(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è)多余的視圖組。)
關(guān)于inflate常用的三個(gè)方法的總結(jié):
- 調(diào)用LayoutInflater.inflate方法,并且將root參數(shù)設(shè)置為null,就等于忽略了xml布局文件中的layout_×參數(shù)(而如gravity、background等這樣的非layout參數(shù)則依然會(huì)生效),并返回布局文件對(duì)應(yīng)的忽略layout_×參數(shù)的view對(duì)象;
- 如果root不為null的話(huà),就根據(jù)root會(huì)為xml布局文件生成一個(gè)LayoutParam對(duì)象,如果attachToRoot參數(shù)為false,那么就將這個(gè)param對(duì)象設(shè)置給這個(gè)布局文件的View;
- 如果root不為null,并且attachRoot=true,那么就會(huì)根據(jù)root生成一個(gè)布局文件View的LayoutParam對(duì)象,并且將這個(gè)View添加到root中去,并返回這個(gè)root的View。
看inflate的源碼可以看出對(duì)三種不同情況的處理:
// resource為inflate方法中傳入的xml布局資源參數(shù)
final XmlResourceParser parser = res.getLayout(resource);
……
final AttributeSet attrs = Xml.asAttributeSet(parser);
……
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
……
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
2. 向Activity中添加Fragment
a. 在 Activity 的布局文件內(nèi)聲明片段
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<fragment
android:id="@+id/list"
android:name="com.example.news.ArticleListFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<fragment
android:id="@+id/viewer"
android:name="com.example.news.ArticleReaderFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2" />
</LinearLayout>
Fragment的android:name屬性指定要在布局中實(shí)例化的Fragment。
當(dāng)系統(tǒng)創(chuàng)建此 Activity 布局時(shí),會(huì)實(shí)例化在布局中指定的每個(gè)Fragment,并為每個(gè)Fragment調(diào)用 onCreateView() 方法,以檢索每個(gè)Fragment的布局。系統(tǒng)會(huì)直接插入Fragment返回的 View
來(lái)替代 fragment 元素。
使用這種方式時(shí),fragment元素的id是必須設(shè)置的,否則會(huì)crash
每個(gè)Fragment都需要一個(gè)唯一的標(biāo)識(shí)符,重啟 Activity 時(shí),系統(tǒng)可以使用該標(biāo)識(shí)符來(lái)恢復(fù)Fragment(您也可以使用該標(biāo)識(shí)符來(lái)捕獲Fragment以執(zhí)行某些事務(wù),如將其刪除)。 可以通過(guò)三種方式為Fragment提供 ID:
- 為 android:id屬性提供唯一 ID
- 為 android:tag屬性提供唯一字符串
- 如果您未給以上兩個(gè)屬性提供值,系統(tǒng)會(huì)使用容器視圖的 ID
這里我測(cè)試發(fā)現(xiàn),這樣的顯示Fragment時(shí),inflate的xml中根ViewGroup的layout_×參數(shù)會(huì)被忽略掉:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/colorPrimary"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:text="我是其他Fragment" />
</LinearLayout>
將上述布局的Fragment添加到一個(gè)Activity的布局中:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/second_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:id="@+id/otherFragment"
android:name="holenzhou.com.aboutfragment.view.OtherFragment"
android:layout_width="match_parent"
android:layout_weight="match_parent"/>
</LinearLayout>
會(huì)發(fā)現(xiàn)寬和高的參數(shù)被忽略掉了,而是以fragment元素的layout參數(shù)為準(zhǔn)了。

Debug發(fā)現(xiàn)此時(shí)OtherFragment的onCreateView()方法中,傳進(jìn)來(lái)的container參數(shù)為null,很奇怪,Google了一番,發(fā)現(xiàn)stackoverflow上面也有類(lèi)似的問(wèn)答,但都沒(méi)有說(shuō)清楚是為什么。
b. 在代碼中動(dòng)態(tài)添加Fragment到某個(gè)現(xiàn)有的ViewGroup
您可以在 Activity 運(yùn)行期間隨時(shí)將Fragment添加到 Activity 布局中。您只需指定要將Fragment放入哪個(gè) ViewGroup。
要想在您的 Activity 中執(zhí)行Fragment事務(wù)(如添加、刪除或替換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。
一旦您通過(guò) FragmentTransaction 做出了更改,就必須調(diào)用 commit() 以使更改生效。
Fragment可以沒(méi)有UI,用作 Activity 的不可見(jiàn)工作線(xiàn)程。添加此類(lèi)型的Fragment,使用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)該方法。
3. 管理Fragment
通過(guò)使用FragmentManager來(lái)管理Activity中的Fragment,可以執(zhí)行的操作包括:
- 通過(guò) findFragmentById()(對(duì)于在 Activity 布局中提供 UI 的Fragment)或 findFragmentByTag()(對(duì)于提供或不提供 UI 的Fragment)獲取 Activity 中存在的Fragment
- 通過(guò) popBackStack()(模擬用戶(hù)發(fā)出的 Back 命令)將片段從返回棧中彈出
- 通過(guò) addOnBackStackChangedListener() 注冊(cè)一個(gè)偵聽(tīng)返回棧變化的偵聽(tīng)器
4. 執(zhí)行Fragment事務(wù)
在 Activity 中使用Fragment的一大優(yōu)點(diǎn)是,可以根據(jù)用戶(hù)行為通過(guò)它們執(zhí)行添加、刪除、替換以及其他操作。 您提交給 Activity 的每組更改都稱(chēng)為事務(wù),您可以使用 FragmentTransaction 中的 API 來(lái)執(zhí)行一項(xiàng)事務(wù)。您也可以將每個(gè)事務(wù)保存到由 Activity 管理的返回棧內(nèi),從而讓用戶(hù)能夠回退Fragment更改(類(lèi)似于回退 Activity)。
每個(gè)事務(wù)都是您想要同時(shí)執(zhí)行的一組更改。您可以使用 add(), replace(), remove() 等方法為給定事務(wù)設(shè)置您想要執(zhí)行的所有更改。然后,要想將事務(wù)應(yīng)用到 Activity,您必須調(diào)用 commit() 。
不過(guò),在您調(diào)用 commit() 之前,您可能想調(diào)用 addToBackStack(),以將事務(wù)添加到Fragment事務(wù)返回棧。 該返回棧由 Activity 管理,允許用戶(hù)通過(guò)按“返回”按鈕返回上一Fragment狀態(tài)。
例如,以下示例說(shuō)明了如何將一個(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(如有)。通過(guò)調(diào)用 addToBackStack() 可將替換事務(wù)保存到返回棧,以便用戶(hù)能夠通過(guò)按“返回”按鈕撤消事務(wù)并回退到上一Fragment。
如果您向事務(wù)添加了多個(gè)更改(如又一個(gè) add() 或 remove()),并且調(diào)用了 addToBackStack(),則在調(diào)用 commit() 前應(yīng)用的所有更改都將作為單一事務(wù)添加到返回棧,并且“返回”按鈕會(huì)將它們一并撤消。
向FragmentTransaction添加更改的順序無(wú)關(guān)緊要,不過(guò):
- 必須最后調(diào)用 commit();
- 如果您要向同一容器添加多個(gè)Fragment,則您添加Fragment的順序?qū)Q定它們?cè)谝晥D層次結(jié)構(gòu)中的出現(xiàn)順序。
如果您沒(méi)有在執(zhí)行刪除Fragment的事務(wù)時(shí)調(diào)用 addToBackStack(),則事務(wù)提交時(shí)該Fragment會(huì)被銷(xiāo)毀,用戶(hù)將無(wú)法回退到該Fragment。 不過(guò),如果您在刪除Fragment時(shí)調(diào)用了 addToBackStack(),則系統(tǒng)會(huì)停止該Fragment,并在用戶(hù)回退時(shí)將其恢復(fù)。
提示:對(duì)于每個(gè)Fragment事務(wù),您都可以通過(guò)在提交前調(diào)用 setTransition() 來(lái)應(yīng)用過(guò)渡動(dòng)畫(huà)。
調(diào)用 commit() 不會(huì)立即執(zhí)行事務(wù),而是在 Activity 的 UI 線(xiàn)程(主線(xiàn)程)可以執(zhí)行該操作時(shí)再安排其在線(xiàn)程上運(yùn)行。不過(guò),如有必要,您也可以從 UI 線(xiàn)程調(diào)用 executePendingTransactions() 以立即執(zhí)行 commit() 提交的事務(wù)。通常不必這樣做,除非其他線(xiàn)程中的作業(yè)依賴(lài)該事務(wù)。
注意:您只能在 Activity保存其狀態(tài)(用戶(hù)離開(kāi) Activity)之前使用 commit() 提交事務(wù)。如果您試圖在該時(shí)間點(diǎn)后提交,則會(huì)引發(fā)異常。 這是因?yàn)槿缧杌謴?fù) Activity,則提交后的狀態(tài)可能會(huì)丟失。 對(duì)于丟失提交無(wú)關(guān)緊要的情況,請(qǐng)使用 commitAllowingStateLoss()。
5. 與Activity通信
- Fragment通過(guò)getActivity()訪(fǎng)問(wèn)Activity實(shí)例,并輕松地執(zhí)行在A(yíng)ctivity布局中查找視圖等任務(wù);
View listView = getActivity().findViewById(R.id.list);
2.Activity中通過(guò)findFragmentById()或者findFragmentByTag(),通過(guò)從FragmentManager獲得對(duì)Fragment的引用來(lái)調(diào)用Fragment中的方法。例如:
ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
6. 創(chuàng)建對(duì) Activity 的事件回調(diào)
為了在Fragment和Activity間共享數(shù)據(jù),可以在Fragment內(nèi)定義一個(gè)回調(diào)接口。并要求宿主 Activity 實(shí)現(xiàn)它。 當(dāng) Activity 通過(guò)該接口收到回調(diào)時(shí),可以根據(jù)需要與布局中的其他Fragment共享這些信息。(比如左邊FragmentA中顯示文章列表,右邊FragmentB中顯示相對(duì)應(yīng)文章內(nèi)容的場(chǎng)景)
public static class FragmentA extends ListFragment {
...
// Container Activity must implement this interface
public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
...
}
在onAttach()回調(diào)中強(qiáng)轉(zhuǎn)宿主Activity為指定接口,Activity實(shí)現(xiàn)接口時(shí),mListener成員會(huì)保留對(duì) Activity 的OnArticleSelectedListener 實(shí)現(xiàn)的引用,以便FragmentA 可以通過(guò)調(diào)用 OnArticleSelectedListener 定義的方法與 Activity 共享事件。
public static class FragmentA extends ListFragment {
OnArticleSelectedListener mListener;
...
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + "must implement OnArticleSelectedListener");
}
}
...
}