Android 學(xué)習(xí)筆記之 Fragment

本文整理自:Google官方文檔中文學(xué)習(xí)手冊(cè),筆者省略了對(duì)自己幫助不大的章節(jié),拜讀原文請(qǐng)點(diǎn)鏈接。

一钠惩、動(dòng)態(tài)創(chuàng)建靈活的 Fragment

1.在運(yùn)行時(shí)向 Activity 添加 Fragment

你可以在 Activity 運(yùn)行時(shí)向其添加 Fragment,而不用使用 <fragment>標(biāo)簽在布局文件中為 Activity 定義 Fragment族阅。如果你打算在 Activity 運(yùn)行周期內(nèi)更改 Fragment篓跛,就必須這樣做。

要執(zhí)行添加或移除 Fragment 等事務(wù)坦刀,你必須使用 FragmentManager 創(chuàng)建一個(gè) FragmentTransaction愧沟,后者可提供用于執(zhí)行添加、移除鲤遥、替換以及其他 Fragment 事務(wù)的 API沐寺。
如果 Activity 中的 Fragment 可以移除和替換,你應(yīng)在調(diào)用 Activity 的 onCreate() 方法期間為 Activity 添加初始 Fragment(s)盖奈。
在處理 Fragment(特別是在運(yùn)行時(shí)添加的 Fragment)時(shí)混坞,請(qǐng)謹(jǐn)記以下重要規(guī)則:必須在布局中為 Fragment 提供 View 容器,以便保存 Fragment 的布局钢坦。
靜態(tài)布局一次只會(huì)顯示一個(gè) Fragment究孕。要用一個(gè) Fragment 替換另一個(gè) Fragment,Activity 的布局中需要包含一個(gè)作為 Fragment 容器的空 FrameLayout爹凹。

res/layout/news_articles.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

在 Activity 中厨诸,用 Support Library API 調(diào)用 getSupportFragmentManager() 以獲取 FragmentManager,然后調(diào)用 beginTransaction() 創(chuàng)建 FragmentTransaction禾酱,然后調(diào)用 add() 添加 Fragment微酬。
你可以使用同一個(gè) FragmentTransaction 對(duì) Activity 執(zhí)行多 Fragment 事務(wù)。當(dāng)你準(zhǔn)備好進(jìn)行更改時(shí)颤陶,必須調(diào)用 commit()颗管。

例如,下面介紹了如何為上述布局添加 Fragment:

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;

public class MainActivity extends FragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.news_articles);

        // 確認(rèn) Activity 使用的布局版本包含 fragment_container FrameLayout
        if (findViewById(R.id.fragment_container) != null) {

            // 不過(guò)指郁,如果我們要從先前的狀態(tài)還原忙上,則無(wú)需執(zhí)行任何操作而應(yīng)返回,否則
            // 就會(huì)得到重疊的 Fragment闲坎。
            if (savedInstanceState != null) {
                return;
            }

            // 創(chuàng)建一個(gè)要放入 Activity 布局中的新 Fragment
            HeadlinesFragment firstFragment = new HeadlinesFragment();

            // 如果此 Activity 是通過(guò) Intent 發(fā)出的特殊指令來(lái)啟動(dòng)的疫粥,
            // 請(qǐng)將該 Intent 的 extras 以參數(shù)形式傳遞給該 Fragment
            firstFragment.setArguments(getIntent().getExtras());

            // 將該 Fragment 添加到“fragment_container” FrameLayout 中
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.fragment_container, firstFragment).commit();
        }
    }
}

由于該 Fragment 已在運(yùn)行時(shí)添加到 FrameLayout 容器中,而不是在 Activity 布局中通過(guò) <fragment>
元素進(jìn)行定義,因此該 Activity 可以移除和替換這個(gè) Fragment。

2.用一個(gè) Fragment 替換另一個(gè) Fragment

替換 Fragment 的步驟與添加 Fragment 的步驟相似达布,但需要調(diào)用 replace() 方法瘩燥,而非 add()溢豆。
請(qǐng)注意,當(dāng)你執(zhí)行替換或移除 Fragment 等 Fragment 事務(wù)時(shí)虑粥,最好能讓用戶(hù)向后導(dǎo)航和“撤消”所做更改很洋。要通過(guò) Fragment 事務(wù)允許用戶(hù)向后導(dǎo)航底哗,你必須調(diào)用 addToBackStack()岁诉,然后再執(zhí)行 FragmentTransaction

注: 當(dāng)你移除或替換 Fragment 并向返回堆棧添加事務(wù)時(shí)跋选,已移除的 Fragment 會(huì)停止(而不是銷(xiāo)毀)涕癣。如果用戶(hù)向后導(dǎo)航,還原該 Fragment前标,它會(huì)重新啟動(dòng)坠韩。如果你沒(méi)有向返回堆棧添加事務(wù),那么該 Fragment 在移除或替換時(shí)就會(huì)被銷(xiāo)毀炼列。

替換 Fragment 的示例:

// 創(chuàng)建 Fragment 并為其添加一個(gè)參數(shù)只搁,用來(lái)指定應(yīng)顯示的文章
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

// 將 fragment_container View 中的內(nèi)容替換為此 Fragment,
// 然后將該事務(wù)添加到返回堆棧俭尖,以便用戶(hù)可以向后導(dǎo)航
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

// 執(zhí)行事務(wù)
transaction.commit();

addToBackStack() 方法可接受可選的字符串參數(shù)氢惋,來(lái)為事務(wù)指定獨(dú)一無(wú)二的名稱(chēng)。除非你打算使用 FragmentManager.BackStackEntry API 執(zhí)行高級(jí) Fragment 操作目溉,否則無(wú)需使用此名稱(chēng)明肮。


二、與其他 Fragment 交互

通常 Fragment 之間可能會(huì)需要交互缭付,比如基于用戶(hù)事件的內(nèi)容變更。所有 Fragment 之間的交互應(yīng)通過(guò)與之關(guān)聯(lián)的 Activity 來(lái)完成循未。兩個(gè) Fragment 之間不應(yīng)直接交互陷猫。

1.定義接口

為了讓 Fragment 與包含它的 Activity 進(jìn)行交互,可以在 Fragment 類(lèi)中定義一個(gè)接口的妖,并在 Activity 中實(shí)現(xiàn)绣檬。該 Fragment 在它的 onAttach() 方法生命周期中獲取該接口的實(shí)現(xiàn),然后調(diào)用接口的方法嫂粟,以便與 Activity 進(jìn)行交互娇未。(若該 Fragment 中實(shí)現(xiàn)了 onAttach() 方法,則會(huì)被自動(dòng)調(diào)用星虹。)

public class HeadlinesFragment extends ListFragment {
    OnHeadlineSelectedListener mCallback;

    // 容器 Activity 必須實(shí)現(xiàn)該接口
    // (譯注:“容器 Activity”意即“包含該 Fragment 的 Activity”)
    public interface OnHeadlineSelectedListener {
        public void onArticleSelected(int position);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // 確認(rèn)容器 Activity 已實(shí)現(xiàn)該回調(diào)接口零抬。否則,拋出異常
        try {
            mCallback = (OnHeadlineSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }

    ...
}

現(xiàn)在 Fragment 可以通過(guò)調(diào)用 mCallback(OnHeadlineSelectedListener 接口的實(shí)例)的 onArticleSelected() 方法(也可以是其它方法)與 Activity 進(jìn)行消息傳遞宽涌。

例如平夜,當(dāng)用戶(hù)點(diǎn)擊列表?xiàng)l目時(shí),F(xiàn)ragment 中的下面的方法將被調(diào)用卸亮。Fragment 用回調(diào)接口將事件傳遞給父 Activity忽妒。

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // 向宿主 Activity 傳送事件
        mCallback.onArticleSelected(position);
    }

2.實(shí)現(xiàn)接口

為了接收回調(diào)事件,宿主 Activity 必須實(shí)現(xiàn)在 Fragment 中定義的接口。

例如段直,下面的 Activity 實(shí)現(xiàn)了上面例子中的接口吃溅。

public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    ...

    public void onArticleSelected(int position) {
        // 用戶(hù)從 HeadlinesFragment 選擇了一篇文章的標(biāo)題
        // 在這里做點(diǎn)什么,以顯示該文章
    }
}

3.向 Fragment 傳遞消息

宿主 Activity 通過(guò) findFragmentById() 獲取 Fragment 的實(shí)例鸯檬,然后直接調(diào)用 Fragment 的 public 方法向 Fragment 傳遞消息罕偎。
例如,假設(shè)上面所示的 Activity 可能包含另一個(gè) Fragment京闰,該 Fragment 用于展示從上面的回調(diào)方法中返回的指定的數(shù)據(jù)颜及。在這種情況下,Activity 可以把從回調(diào)方法中接收到的信息傳遞到這個(gè)展示數(shù)據(jù)的 Fragment蹂楣。

public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    ...

    public void onArticleSelected(int position) {
        // 用戶(hù)從 HeadlinesFragment 選擇了一篇文章的標(biāo)題
        // 在這里做點(diǎn)什么俏站,以顯示該文章

        ArticleFragment articleFrag = (ArticleFragment)
                getSupportFragmentManager().findFragmentById(R.id.article_fragment);

        if (articleFrag != null) {
            // 若 articleFrag 有效,則表示我們正在處理兩格布局(two-pane layout)……

            // 調(diào)用 ArticleFragment 的方法痊土,以更新其內(nèi)容
            articleFrag.updateArticleView(position);
        } else {
            // 否則肄扎,我們正在處理單格布局(one-pane layout)。此時(shí)需要 swap frags...

            // 創(chuàng)建 Fragment赁酝,向其傳遞包含被選文章的參數(shù)
            ArticleFragment newFragment = new ArticleFragment();
            Bundle args = new Bundle();
            args.putInt(ArticleFragment.ARG_POSITION, position);
            newFragment.setArguments(args);

            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

            // 無(wú)論 fragment_container 視圖里是什么犯祠,用該 Fragment 替換它。并將
            // 該事務(wù)添加至回棧酌呆,以便用戶(hù)可以往回導(dǎo)航(譯注:回棧衡载,即 Back Stack。
            // 在有多個(gè) Activity 的 APP 中隙袁,將這些 Activity 按創(chuàng)建次序組織起來(lái)的
            // 棧痰娱,稱(chēng)為回棧)
            transaction.replace(R.id.fragment_container, newFragment);
            transaction.addToBackStack(null);

            // 執(zhí)行事務(wù)
            transaction.commit();
        }
    }
}

不要給自己的人生設(shè)限
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市菩收,隨后出現(xiàn)的幾起案子梨睁,更是在濱河造成了極大的恐慌,老刑警劉巖娜饵,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坡贺,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡箱舞,警方通過(guò)查閱死者的電腦和手機(jī)遍坟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)褐缠,“玉大人政鼠,你說(shuō)我怎么就攤上這事《游海” “怎么了公般?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵万搔,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我官帘,道長(zhǎng)瞬雹,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任刽虹,我火速辦了婚禮酗捌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘涌哲。我一直安慰自己胖缤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布阀圾。 她就那樣靜靜地躺著哪廓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪初烘。 梳的紋絲不亂的頭發(fā)上涡真,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音肾筐,去河邊找鬼哆料。 笑死,一個(gè)胖子當(dāng)著我的面吹牛吗铐,可吹牛的內(nèi)容都是我干的东亦。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼抓歼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼讥此!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起谣妻,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎卒稳,沒(méi)想到半個(gè)月后蹋半,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡充坑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年减江,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捻爷。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辈灼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出也榄,到底是詐尸還是另有隱情巡莹,我是刑警寧澤司志,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站降宅,受9級(jí)特大地震影響骂远,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腰根,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一激才、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧额嘿,春花似錦瘸恼、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至捕儒,卻和暖如春冰啃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背刘莹。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工阎毅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人点弯。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓扇调,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親抢肛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子狼钮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容