Fragment專題

Fragment是什么?

Fragment是Android3.0后引入的一個新的API贰健,他出現(xiàn)的初衷是為了適應大屏幕的平板電腦胞四, 當然現(xiàn)在他仍然是平板APP UI設計的寵兒,而且我們普通手機開發(fā)也會加入這個Fragment伶椿, 我們可以把他看成一個小型的Activity辜伟,又稱Activity片段!想想导狡,如果一個很大的界面枚赡,我們 就一個布局料皇,寫起界面來會有多麻煩娜膘,而且如果組件多的話是管理起來也很麻煩匕争!而使用Fragment 我們可以把屏幕劃分成幾塊跑杭,然后進行分組,進行一個模塊化的管理惹盼!從而可以更加方便的在 運行過程中動態(tài)地更新Activity的用戶界面枉昏!另外Fragment并不能單獨使用晰奖,他需要嵌套在Activity 中使用蛆楞,盡管他擁有自己的生命周期,但是還是會受到宿主Activity的生命周期的影響,比如Activity 被destory銷毀了播演,他也會跟著銷毀!

靜態(tài)使用Fragment

  1. 繼承Fragmentt或者它的子類崖瞭,重寫onCreateView決定Fragemnt的布局雌续。
public class FirstFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view=inflater.inflate(R.layout.fragment_first, container, false);
        TextView tv_hello= (TextView) view.findViewById(R.id.tv_hello);
        tv_hello.setText("MyFirstFragment");
        return view;
    }
}

布局代碼:

<TextView
        android:id="@+id/tv_hello"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="HelloWorld" />
  1. 在Activity中使用此Fragment核畴,就當和使用普通的View一樣温学。
    使用Fragment的Activity的布局代碼:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lg.www.blog.MainActivity">
    <fragment
        android:id="@+id/fragment1"
        android:name="com.lg.www.blog.FirstFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />
</RelativeLayout>
  • Fragment是在android3.0版本引入的,如果你使用的是3.0之前的系統(tǒng),需要先導入android-support-v4的jar包才能使用Fragment功能,所在的那個Activity就要繼承FragmentActivity,且Fragment的方法都要使用帶Support的那個(如getSupportFragmentManager()方法);本專題里面所有的Fragment都是沒有兼容3.0之前版本的炎码。

動態(tài)使用Fragment

  1. 將靜態(tài)使用時的Activity的布局代碼上的fragment刪除辖众。
  2. 動態(tài)加載流程圖:


    29546434.jpg
  3. 關鍵代碼:
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        FirstFragment fragment = new FirstFragment();
        getFragmentManager().beginTransaction().add(R.id.activity_main, fragment).commit();
    }
}

Fragment的生命周期圖

31722863.jpg
  • Fragment需要嵌套在Activity中使用,當然也可以嵌套到另外一個Fragment中,但這個被嵌套 的Fragment也是需要嵌套在Activity中的,間接地說,Fragment還是需要嵌套在Activity中! 受寄主Activity的生命周期影響,當然他也有自己的生命周期!另外不建議在Fragment里面 嵌套Fragment因為嵌套在里面的Fragment生命周期不可控!
  • 官方文檔說創(chuàng)建Fragment時至少需要實現(xiàn)三個方法:onCreate( ),onCreateView( ),OnPause( ); 不過貌似只寫一個onCreateView也是可以的瓢捉;除了onCreateView方法频丘,其他的所有方法如果你重寫了,必須調(diào)用父類對于該方法的實現(xiàn)泡态。
  • 停止狀態(tài)的fragment仍然活著(所有狀態(tài)和成員信息被系統(tǒng)保持著),然而,它對用戶不再可見,并且如果activity被干掉,他也會被干掉.
  • 走一趟生命周期圖:
    ①Activity加載Fragment的時候,依次調(diào)用下面的方法: onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart ->onResume
    ②當我們弄出一個懸浮的對話框風格的Activity,或者其他,就是讓Fragment所在的Activity可見,但不獲得焦點 onPause
    ③當對話框關閉,Activity又獲得了焦點: onResume
    ④當我們替換Fragment,并調(diào)用addToBackStack()將他添加到Back棧中 onPause -> onStop -> onDestoryView B!注意,此時的Fragment還沒有被銷毀哦!!!
    ⑤當我們按下鍵盤的回退鍵某弦,F(xiàn)ragment會再次顯示出來: onCreateView -> onActivityCreated -> onStart -> onResume
    ⑥如果我們替換后,在事務commit之前沒有調(diào)用addToBackStack()方法將 Fragment添加到back棧中的話;又或者退出了Activity的話,那么Fragment將會被完全結(jié)束, Fragment會進入銷毀狀態(tài) onPause -> onStop -> onDestoryView -> onDestory -> onDetach

Fragment管理與Fragment事務

97188171.jpg
  1. Fragment常用的三個類:
    android.app.Fragment 主要用于定義Fragment
    android.app.FragmentManager 主要用于在Activity中操作Fragment
    android.app.FragmentTransaction 保證一些列Fragment操作的原子性桐汤,熟悉事務這個詞,一定能明白靶壮。
  2. 獲取FragmentManage的方式:
    getFragmentManager() 怔毛,v4中,getSupportFragmentManager
  3. 主要的操作:都是FragmentTransaction的方法
    FragmentTransaction transaction = fm.benginTransatcion();//開啟一個事務
  • transaction.add()
    往Activity中添加一個Fragment
  • transaction.remove()
    從Activity中移除一個Fragment腾降,如果被移除的Fragment沒有添加到回退棧(回退棧后面會詳細說)拣度,這個Fragment實例將會被銷毀。
  • transaction.replace()
    使用另一個Fragment替換當前的,實際上就是remove()抗果,然后add()的合體
  • transaction.hide()
    隱藏當前的Fragment筋帖,僅僅是設為不可見,并不會銷毀
  • transaction.show()
    顯示之前隱藏的Fragment
  • transaction.detach()
    會將view從UI中移除,和remove()不同,此時fragment的狀態(tài)依然由FragmentManager維護窖张。
  • transaction.attach()
    重建view視圖幕随,附加到UI上并顯示蚁滋。
    transatcion.commit()//提交一個事務宿接,在一個事務開啟到提交可以進行多個的添加、移除辕录、替換等操作睦霎。
  1. 值得注意的是:如果你喜歡使用Fragment,一定要清楚這些方法走诞,哪個會銷毀視圖副女,哪個會銷毀實例,哪個僅僅只是隱藏蚣旱,這樣才能更好的使用它們碑幅。
    a、比如:我在FragmentA中的EditText填了一些數(shù)據(jù)塞绿,當切換到FragmentB時沟涨,如果希望會到A還能看到數(shù)據(jù),則適合你的就是hide和show异吻;也就是說裹赴,希望保留用戶操作的面板,你可以使用hide和show诀浪,當然了不要使勁在那new實例棋返,進行下非null判斷。
    b雷猪、再比如:我不希望保留用戶操作睛竣,你可以使用remove(),然后add()求摇;或者使用replace()這個和remove,add是相同的效果射沟。
    c、remove和detach有一點細微的區(qū)別月帝,在不考慮回退棧的情況下躏惋,remove會銷毀整個Fragment實例,而detach則只是銷毀其視圖結(jié)構(gòu)嚷辅,實例并不會被銷毀簿姨。那么二者怎么取舍使用呢?如果你的當前Activity一直存在,那么在不希望保留用戶操作的時候扁位,你可以優(yōu)先使用detach准潭。
    d、在Activity的onCreate方法里面調(diào)用transaction.add() 方法添加Fragment時進行如下處理:
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main);  
        if(savedInstanceState == null) {  
            //只有當savedInstanceState == null才調(diào)用transaction.add() 方法
            transaction.add(...) ;
        } 
    }  

這樣做的目的是為了避免重復實例化一個相同的新的Fragment并重復添加到Activity上域仇,因為當某些原因(屏幕旋轉(zhuǎn)刑然,長時間處于后臺等)Activity重新調(diào)用onCreate恢復頁面時,它會從savedInstanceState中取出原來保存的數(shù)據(jù)(包括Fragment的實例)進行恢復暇务,這個時候就不必重新new了泼掠,Android系統(tǒng)會自動把保存的數(shù)據(jù)取出并還原的。

Fragment回退棧

類似與Android系統(tǒng)為Activity維護一個任務棧垦细,我們也可以通過Activity維護一個回退棧來保存每次Fragment事務發(fā)生的變化择镇。如果你將Fragment任務添加到回退棧,當用戶點擊后退按鈕時括改,將看到上一次的保存的Fragment腻豌。一旦Fragment完全從后退棧中彈出,用戶再次點擊后退鍵嘱能,則退出當前Activity吝梅。

  • 添加到回退棧的方法:FragmentTransaction.addToBackStack(String);
    eg:FragmentTransaction.addToBackStack(null);
  • 根Fragment(第一個添加到Activity的Fragment)一般不添加到回退棧當中,因為如果根Fragment綁定的Activity上面沒有任何UI控件的話惹骂,點擊Back鍵將返回上一次的保存的Fragment苏携,這時候由于這個Fragment已經(jīng)是最根部Fragment了,就會返回到空白的Activity界面了析苫。
  • 使用replace方法切換Fragment時(replace是remove和add的合體)兜叨,如果不添加事務到回退棧,前一個Fragment實例會被銷毀衩侥。調(diào)用FragmentTransaction.addToBackStack(null)將當前的事務添加到回退棧后国旷,前一個Fragment實例不會被銷毀,但是視圖層次依然會被銷毀茫死,即會調(diào)用前一個Fragment的onDestoryView方法和替換Fragment的onCreateView方法跪但。

Fragment與Activity的交互

45971686.jpg
  1. 組件獲取
  • Fragment獲得Activity中的組件: getActivity().findViewById(R.id.list);
  • Fragment中獲得Context的方法:getActivity()峦萎;
  • Activity獲得Fragment中的組件(根據(jù)id和tag都可以):
    getFragmentManager().findFragmentById(R.id.fragment1);
    getFragmentManager().findFragmentByTag("fragment1") ;
  1. 數(shù)據(jù)傳遞
    ①Activit傳遞數(shù)據(jù)給Fragment:
    在Activity中創(chuàng)建Bundle數(shù)據(jù)包,調(diào)用Fragment實例的setArguments(bundle) 從而將Bundle數(shù)據(jù)包傳給Fragment,然后Fragment中調(diào)用getArguments獲得 Bundle對象,然后進行解析就可以了屡久。
    ②Fragment傳遞數(shù)據(jù)給Activity
    在Fragment中定義一個內(nèi)部回調(diào)接口,再讓包含該Fragment的Activity實現(xiàn)該回調(diào)接口, Fragment就可以通過回調(diào)接口傳數(shù)據(jù)了,其實就是接口回調(diào)。
    Step 1:定義一個回調(diào)接口:(Fragment中)
/*接口*/  
public interface CallBack{  
    /*定義一個獲取信息的方法*/  
    public void getResult(String result);  
}  

Step 2:接口回調(diào)(Fragment中)

 /*本地私有回調(diào)接口爱榔,調(diào)用出通過回調(diào)接口方法傳入*/
    private CallBack mCallback;
    /*設置回調(diào)接口*/
    public void getData(CallBack callBack){
        this.mCallback=callBack;
    }
    /*將需要傳遞給Activity數(shù)據(jù)的地方將數(shù)據(jù)msg傳遞過去*/
    mCallback.getResult(msg);

Step 3:使用接口回調(diào)方法讀數(shù)據(jù)(Activity中)

/* 使用接口回調(diào)的方法獲取數(shù)據(jù) */  
fragment.getData(new FirstFragment.CallBack() {
            @Override
            public void getResult(String result) {
                //將回傳數(shù)據(jù)進行處理
            }
});
  • 在Fragment定義接口的抽象方法時,你要傳什么類型的數(shù)據(jù)參數(shù)就設置什么類型;
    ③Fragment與Fragment之間的數(shù)據(jù)互傳
    其實這很簡單,找到要接受數(shù)據(jù)的fragment對象,直接調(diào)用setArguments傳數(shù)據(jù)進去就可以了 通常的話是replace時,即fragment跳轉(zhuǎn)的時候傳數(shù)據(jù)的,那么只需要在初始化要跳轉(zhuǎn)的Fragment 后調(diào)用他的setArguments方法傳入數(shù)據(jù)即可!
    如果是兩個Fragment需要即時傳數(shù)據(jù),而非跳轉(zhuǎn)的話,就需要先在Activity獲得f1傳過來的數(shù)據(jù), 再傳到f2了,就是以Activity為媒介被环。

使用Fragment.setArguments(Bundle bundle)來傳遞參數(shù)

首先我們來看下AndroidStudio提供的創(chuàng)建BlankFragment的工廠方法代碼:

 /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     * @param param1 Parameter 1.
     * @param param2 Parameter 2.
     * @return A new instance of fragment BlankFragment.
     */
    // TODO: Rename and change types and number of parameters
    public static BlankFragment newInstance(String param1, String param2) {
        BlankFragment fragment = new BlankFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

從中我們可以看到官方建議我們用這種方法創(chuàng)建Fragment,這樣可以傳遞參數(shù)給Fragment详幽。但是為什么不推薦我們使用帶參的構(gòu)造方法傳遞參數(shù)呢筛欢?
原因就是因為當設備配置參數(shù)發(fā)生變化浸锨,如橫豎屏切換時,系統(tǒng)會重新恢復(會從savedInstanceState中取出原來保存的數(shù)據(jù)版姑,包括Activity柱搜、Fragment的實例進行恢復)創(chuàng)建Activity,同時也會重新構(gòu)建它所管理的Fragment(默認調(diào)用無參的那個構(gòu)造方法進行創(chuàng)建)剥险,原先的Fragment構(gòu)造方法傳遞過來的參數(shù)將會全部丟失聪蘸,但是通過Fragment.setArguments(Bundle bundle)方法設置的bundle會通過savedInstanceState保留下來。所以盡量使用Fragment.setArguments(Bundle bundle)方式來傳遞參數(shù)表制。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末健爬,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子夫凸,更是在濱河造成了極大的恐慌浑劳,老刑警劉巖阱持,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夭拌,死亡現(xiàn)場離奇詭異,居然都是意外死亡衷咽,警方通過查閱死者的電腦和手機鸽扁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镶骗,“玉大人桶现,你說我怎么就攤上這事《︽ⅲ” “怎么了骡和?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長相寇。 經(jīng)常有香客問我慰于,道長,這世上最難降的妖魔是什么唤衫? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任婆赠,我火速辦了婚禮,結(jié)果婚禮上佳励,老公的妹妹穿的比我還像新娘休里。我一直安慰自己,他們只是感情好赃承,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布妙黍。 她就那樣靜靜地躺著,像睡著了一般瞧剖。 火紅的嫁衣襯著肌膚如雪拭嫁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音噩凹,去河邊找鬼巴元。 笑死,一個胖子當著我的面吹牛驮宴,可吹牛的內(nèi)容都是我干的逮刨。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼堵泽,長吁一口氣:“原來是場噩夢啊……” “哼修己!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起迎罗,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤睬愤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后纹安,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尤辱,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年厢岂,在試婚紗的時候發(fā)現(xiàn)自己被綠了光督。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡塔粒,死狀恐怖结借,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卒茬,我是刑警寧澤船老,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站圃酵,受9級特大地震影響柳畔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜辜昵,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一荸镊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧堪置,春花似錦躬存、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至坎匿,卻和暖如春盾剩,著一層夾襖步出監(jiān)牢的瞬間雷激,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工告私, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留屎暇,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓驻粟,卻偏偏與公主長得像根悼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蜀撑,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

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

  • Fragment概述 Fragment是Activity中用戶界面的一個行為或者說是一部分挤巡。主要是支持大屏幕上動態(tài)...
    wangling90閱讀 11,522評論 5 76
  • Fragment的應用真的是越來越廣泛了,之前Android在3.0版本加入Fragment的時候酷麦,主要是為了解決...
    閑庭閱讀 2,846評論 0 10
  • 《Android Fragment完全解析矿卑,關于碎片你所需知道的一切》 我們都知道,Android上的界面展示都是...
    cxm11閱讀 2,176評論 2 19
  • 本書從身體效能的角度沃饶,告訴我們?nèi)绾卧诿鎸σ患虑闀r母廷,怎么才能把身體調(diào)整到一種巔峰狀態(tài),進而對時間進行高效的利用绍坝。 ...
    何舒卉閱讀 636評論 0 5
  • 為什么會有這種感慨徘意? 因為這是個正常不過的事情。 這段時間轩褐,在這個職位上,我?guī)缀趺刻於紩覆灰粯拥腻e或者走到一些彎...
    腳下日月閱讀 381評論 1 7