Fragment學(xué)習(xí)及簡單實踐

本文主要介紹下Android Fragment的生命周期绞铃,相關(guān)的API以及和Activity通信的簡單實踐

一哎垦、生命周期:

fragment_lifecycle.png

Fragment創(chuàng)建銷毀時,fragment和所依賴的activity生命周期的執(zhí)行順序恃疯,注意看log的TAG

1.創(chuàng)建時

01-12 17:57:24.823 28028-28028/? I/ActivityLife: onCreate...
01-12 17:57:24.843 28028-28028/? I/FragmentLife: onAttach...
01-12 17:57:24.843 28028-28028/? I/FragmentLife: onCreate...
01-12 17:57:24.843 28028-28028/? I/FragmentLife: onCreateView...
01-12 17:57:24.843 28028-28028/? I/FragmentLife: onActivityCreated...
01-12 17:57:24.843 28028-28028/? I/ActivityLife: onStart...
01-12 17:57:24.843 28028-28028/? I/FragmentLife: onStart...
01-12 17:57:24.843 28028-28028/? I/ActivityLife: onResume...
01-12 17:57:24.843 28028-28028/? I/FragmentLife: onResume...

2.銷毀時

01-12 17:57:40.583 28028-28028/? I/FragmentLife: onPause...
01-12 17:57:40.583 28028-28028/? I/ActivityLife: onPause...
01-12 17:57:40.883 28028-28028/? I/FragmentLife: onStop...
01-12 17:57:40.883 28028-28028/? I/ActivityLife: onStop...
01-12 17:57:40.883 28028-28028/? I/FragmentLife: onDestroyView...
01-12 17:57:40.883 28028-28028/? I/FragmentLife: onDestroy...
01-12 17:57:40.883 28028-28028/? I/FragmentLife: onDetach...
01-12 17:57:40.883 28028-28028/? I/ActivityLife: onDestroy...

二漏设、Activity中,F(xiàn)ragment的2種加載方法

1.靜態(tài)加載

(1)創(chuàng)建Fragment類和布局文件(fragment1.xml)

public class Fragment1 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
       return inflater.inflate(R.layout.fragment1, container, false);
    }
}

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00ff00" >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is fragment 1"
        android:textColor="#000000"
        android:textSize="25sp" />
</LinearLayout> 

(2)在activity布局文件(activity_main.xml)中添加fragment布局

...
<fragment
android:id="@+id/fragment1"
android:name="com.example.sven.fragementdemo.Fragment1"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1" />
...

2.動態(tài)加載

(1) 在activity布局文件中添加FragmentLayout節(jié)點

...
  <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </FrameLayout>
...

(2) java代碼中動態(tài)加載

...
  1.獲取fragmentManager
FragmentManager fragmentManager = getFragmentManager();
  2.獲取FragmentTransaction
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
  3.創(chuàng)建需要的Fragment
Fragment fragment = new Fragment1();
  4.動態(tài)添加fragment
    將創(chuàng)建的fragment添加到Activity布局文件中定義的占位符中(FrameLayout)
fragmentTransaction.add(R.id.fragment_container,fragment).commit();
...

三今妄、FragmentTransaction方法解析結(jié)合Fragment的生命周期

對Fragment的操作主要是通過調(diào)用FragmentTransaction類的方法進(jìn)行的郑口,F(xiàn)ragmentTransaction的對象通常是通過getFragmentManager().beginTransaction()獲取的

1.add & remove / replace

(1) add 往Activity中添加一個Fragment,對應(yīng)的fragment的生命周期如下:

06-13 12:01:43.406 1986-1986/? I/Fragment3: onAttach
06-13 12:01:43.406 1986-1986/? I/Fragment3: onCreate
06-13 12:01:43.406 1986-1986/? I/Fragment3: onCreateView
06-13 12:01:43.406 1986-1986/? I/Fragment3: onActivityCreated
06-13 12:01:43.406 1986-1986/? I/Fragment3: onStart
06-13 12:01:43.406 1986-1986/? I/Fragment3: onResume  

(2) remove 從Activity中移除一個Fragment盾鳞,和add配對使用犬性,通常是直接用replace

06-13 12:07:54.046 8765-8765/com.example.sven.fragementdemo I/Fragment3: onPause
06-13 12:07:54.046 8765-8765/com.example.sven.fragementdemo I/Fragment3: onStop
06-13 12:07:54.046 8765-8765/com.example.sven.fragementdemo I/Fragment3: onDestroyView
06-13 12:07:54.046 8765-8765/com.example.sven.fragementdemo I/Fragment3: onDestroy
06-13 12:07:54.046 8765-8765/com.example.sven.fragementdemo I/Fragment3: onDetach

(3) replace 使用另一個fragment替換當(dāng)前的,先remove掉當(dāng)前的再add新的腾仅,參考add和remove的過程

2.attach & detach

(1) attach 重建view視圖乒裆,添加到UI上并顯示,和detach配合使用推励,顯示一個被detach的fragment

06-13 11:57:46.376 29992-29992/com.example.sven.fragementdemo I/Fragment3: onCreateView
06-13 11:57:46.376 29992-29992/com.example.sven.fragementdemo I/Fragment3: onActivityCreated
06-13 11:57:46.376 29992-29992/com.example.sven.fragementdemo I/Fragment3: onStart
06-13 11:57:46.376 29992-29992/com.example.sven.fragementdemo I/Fragment3: onResume

(2) detach 會將view從UI中移除,和remove()不同,此時fragment的狀態(tài)依然由FragmentManager維護(hù)鹤耍,fragment的實例還存在,但是視圖被銷毀了

06-13 11:58:13.486 29992-29992/com.example.sven.fragementdemo I/Fragment3: onPause
06-13 11:58:13.486 29992-29992/com.example.sven.fragementdemo I/Fragment3: onStop
06-13 11:58:13.486 29992-29992/com.example.sven.fragementdemo I/Fragment3: onDestroyView

3.hide & show

不涉及fragment生命周期验辞,調(diào)試過程中沒有看到想象中onPause稿黄、onStop、onResume函數(shù)的調(diào)用過程跌造,hide時fragment的視圖和實例都不會被銷毀杆怕,只是視圖可見與不可見的變化。賬號登陸界面應(yīng)該用的比較多壳贪,能夠保存用戶的輸入陵珍,和detach區(qū)別就是detach不能夠的保存界面的信息(例如EditText的輸入),每次detach撑碴,attch時界面都會重繪

4.commit

提交對fragment的一系列操作撑教。注意每一次對fragment的操作都要開一次事務(wù),commit一次醉拓。commit和FragmentManager.beginTransaction()要配對使用伟姐。(很像數(shù)據(jù)庫收苏,暫時沒深入研究)

5.addToBackStack(String)

把當(dāng)前事務(wù)的變化情況添加到回退棧,下節(jié)詳細(xì)講下

tips:

1.以上這些方法通常是在Activity中使用,依附于同一個Activity的多個fragment的各種切換
2.fragment真正的實例其實是要通過FragmentTransaction.add愤兵,只有在add時才會執(zhí)行onCreate鹿霸,new的時候拿到只是一個引用 并沒有執(zhí)行生命周期函數(shù)
3.使用attach/detach 或者 hide/show 都需要new出對象,并且執(zhí)行add
4.add/remove/replace/hide/show后都要commit其效果才會在屏幕上顯示出來

四秆乳、Fragment的回退棧

Fragment的會退棧是用來保存每一次Fragment事務(wù)發(fā)生的變化懦鼠,如果你將Fragment任務(wù)添加到回退棧,當(dāng)點擊back鍵時屹堰,將看到上一次的保存的Fragment肛冶,一旦Fragment完全從后退棧中彈出,用戶再次點擊后退鍵扯键,則退出當(dāng)前Activity睦袖,如果被移除的Fragment沒有添加到回退棧,例如執(zhí)行remove或者replace時荣刑,這個Fragment實例將會被銷毀

理解以下3種情況 在同一個Actity中馅笙,fragment1 跳轉(zhuǎn)到fragment2,然后按back退出時的不同情況

public void jump2fragment2(){
    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
    fragment之間跳轉(zhuǎn)時
    1.只采用replace 實例會被銷毀 back鍵一次
    fragmentTransaction.replace(R.id.fragment_container,new Fragment2());
    fragmentTransaction.addToBackStack(null);

    2.把當(dāng)前事務(wù)的變化情況添加到回退棧,視圖會被銷毀但是實例還在(back 2次)
    fragmentTransaction.replace(R.id.fragment_container,new Fragment2());
    fragmentTransaction.addToBackStack(null);

    3.采用hide方式 實例不會被銷毀,視圖也不會被銷毀(back 2次)
    fragmentTransaction.hide(this);
    fragmentTransaction.add(R.id.fragment_container, new Fragment2());
    fragmentTransaction.addToBackStack(null);
    fragmentTransaction.commit();
}

五厉亏、Fragment與Activity之間的通信

1.一般Fragment依附于Activity存在董习,因此與Activity之間的通信可以歸納為以下3點:

(1)Fragment中可以通過getActivity得到當(dāng)前綁定的Activity的實例,然后進(jìn)行操作

例如你在想在某個fragment中通過activity拿到fragment1的數(shù)據(jù)可以這樣做

public void getfragment1text() {
    getActivity().findViewById(R.id.fragment1_text)
}

(2) 如果你Activity中包含自己管理的Fragment的引用爱只,可以通過引用直接訪問所有的Fragment的public方法

(3) 如果Activity中未保存任何Fragment的引用皿淋,那么沒關(guān)系,每個Fragment都有一個唯一的TAG或者ID,可以通過getFragmentManager.findFragmentByTag()或者findFragmentById()獲得任何Fragment實例虱颗,然后進(jìn)行操作 fragment的id其實是無法設(shè)置的沥匈,add或replace時設(shè)置的id是其實要插入fragment所在ViewGroup的id,tag可以在add或replace時設(shè)置忘渔。https://stackoverflow.com/questions/9363072/android-set-fragment-id

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "ActivityLife";
    private Fragment1 fragment = new Fragment1();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        printLog("onCreate...");
        setContentView(R.layout.activity_main);

        // 1.獲取fragmentManager
        FragmentManager fragmentManager = getFragmentManager();
        // 2.獲取FragmentTransaction
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        // 3.創(chuàng)建需要的Fragment
        // Fragment fragment = new Fragment1();
        // 4.動態(tài)添加fragment
        // 將創(chuàng)建的fragment添加到Activity布局文件中定義的占位符中(FrameLayout)
        fragmentTransaction.add(R.id.fragment_container, fragment, "fragment1").commit();
    }

    public void getFragmentMessage(View view){
        //1.針對第2種情況
        fragment.printSth();
        //2.針對第3種情況
        Fragment fragment = getFragmentManager().findFragmentByTag("fragment1");
        printLog(fragment.toString());
        fragment.onResume();
    }
}

public class Fragment1 extends Fragment {
    ...
    public void printSth() {
        Log.i(TAG,"fragment3 printSth");
    }
}

(4)更復(fù)雜的用法參考:

http://blog.csdn.net/lmj623565791/article/details/37992017

2.應(yīng)用場景主要就是通過Activity去管理多個Fragment的狀態(tài)

思路如下:

(1) 讓各個Fragment注冊一個監(jiān)聽接口高帖,讓Activity去implements這個監(jiān)聽接口

(2) 在Activity中new出各個Fragment的對象,獲取引用

(3) 將Fragment中的事件通過listener傳遞到Activity中畦粮,在Fragment中通過getActivity去調(diào)用監(jiān)聽方法

tips:

Fragment中的按鈕的事件響應(yīng)時不能通過在配置文件中加onClick屬性找到的散址,必須注冊onClickListenr(有2種方式)

原因參考:http://blog.csdn.net/Zafir6453/article/details/51383915

3.以上這些自己寫了個Demo,方便大家調(diào)試和學(xué)習(xí)

http://download.csdn.net/detail/time_traveller14/9870932
1.生命周期宣赔,回退棧预麸,參考fragment1,fragment2,MainActivity
2.FragmentTransaction及和Activity通信(fragment中不同的按鈕事件響應(yīng)) 參考fragment3,fragment4, Main2Activity

六.還未理解問題:

1.回退棧的使用場景,有了hide和detach為何還要加這個儒将,僅僅是為了多按一次back鍵吏祸?
2.hide和show為何沒有onPause和onResume的過程,hide為何不執(zhí)行onPause钩蚊,onStop呢贡翘?
3.remove 的真正含義銷毀還是出棧蹈矮,看許多資料解釋是銷毀掉,但為何remove掉鸣驱,commit完fragment!=null泛鸟,還能夠通過tag獲取到,但是去尋找fragment的視圖元素會報錯踊东?
4.屏幕旋轉(zhuǎn)時北滥,已經(jīng)判斷了onSavedInstance==null,為何還會繼續(xù)闸翅,log中 onCreate onCreateView會執(zhí)行再芋,要結(jié)合activity?

參考資料:

https://developer.android.com/guide/components/fragments.html
郭霖大神 http://blog.csdn.net/guolin_blog/article/details/8881711
鴻洋大神 http://blog.csdn.net/lmj623565791/article/details/37970961

自己的第一篇技術(shù)博客坚冀,請大家多多指教祝闻,最后不理解的問題,歡迎討論遗菠!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市华蜒,隨后出現(xiàn)的幾起案子辙纬,更是在濱河造成了極大的恐慌,老刑警劉巖叭喜,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贺拣,死亡現(xiàn)場離奇詭異,居然都是意外死亡捂蕴,警方通過查閱死者的電腦和手機(jī)譬涡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來啥辨,“玉大人涡匀,你說我怎么就攤上這事溉知。” “怎么了级乍?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長玫荣。 經(jīng)常有香客問我甚淡,道長,這世上最難降的妖魔是什么贯卦? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮脸侥,結(jié)果婚禮上建邓,老公的妹妹穿的比我還像新娘。我一直安慰自己睁枕,他們只是感情好官边,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布外遇。 她就那樣靜靜地躺著,像睡著了一般跳仿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上妄辩,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天山上,我揣著相機(jī)與錄音眼耀,去河邊找鬼佩憾。 笑死,一個胖子當(dāng)著我的面吹牛楞黄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鬼廓,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼婶恼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了勾邦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤萎河,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后玛歌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡擎椰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了达舒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡昨登,死狀恐怖贯底,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情禽捆,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布得湘,位于F島的核電站顿仇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏臼闻。R本人自食惡果不足惜囤采,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乓搬。 院中可真熱鬧代虾,春花似錦进肯、人聲如沸棉磨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抬吟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間危队,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工交掏, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留刃鳄,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓挪鹏,卻偏偏與公主長得像愉烙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子步责,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

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