Android--Fragment你應該明白的一些疑難點

美女圖集02android

Fragment概述app

Fragment是Activity中用戶界面的一個行爲或者說是一部分。主要是支持大屏幕上動態顯示和更爲靈活的去組合或是交換UI組件,經過將Activity的佈局分割成若干個fragment,能夠在運行時編輯activity的呈現,而且那些變化會被保存在由activity管理的後臺棧裏面。
Fragment必須老是被嵌入到一個activity之中,而且fragment的生命週期直接接受其宿主activity的生命週期的影響。你能夠認爲fragment是activity的一個模塊零件,它有本身的生命週期,接收它本身的輸入的事件,而且能夠在activity運行時添加或者刪除。
應該將每個fragment設計爲模塊化和可複用化的activity組件。也就是說,你能夠在多個activity中引用同一個fragment,由於fragment定義了它本身的佈局,而且使用它自己生命週期回調的行爲。ide

  • 先看fragment生命週期圖:模塊化

     

    Fragment週期圖函數

  • 在看Fragment依附於Activity的生命狀態圖:佈局

     

    Fragment和Activity生命週期綜合圖學習

Fragment生命週期中的那麼多方法,快來學習一下吧!go go gothis

Fragment生命週期方法含義:編碼

  • public void onAttach(Context context)
    onAttach()方法會在Fragment與Activity窗口關聯後馬上調用。從該方法開始,就能夠經過Fragment.getActivity()方法獲取與Fragment關聯的Activtiy窗口對象,但由於Fragment的控件未初始化,因此不可以操做控件。
  • public void onCreate(Bundle savedInstanceState)
    在調用完onAttach()執行完以後,當即就會調用onCreate()方法,能夠在Bundle對象中獲取一些在Activity中傳過來的數據。一般會在該方法中讀取保存的轉態,獲取或初始化一些數據。在該方法中不要進行耗時操做,否則Activity窗口不會顯示。
  • public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
    該方法是Fragment很重要的一個生命週期方法,由於會在該方法中建立Fragment顯示的View,其中inflater是用來裝載佈局文件的,container是<fragment>標籤的父標籤對應對象,saveInstanceState參數能夠獲取Fragment保存的轉態,若是未保存那麼就爲null。
  • public void onViewCreated(View view,Bundle savedInstanceState)
    Android在建立完Fragment中的View對象以後,會馬上回調該方法。其中view參數就是onCreateView中返回的view,而bundle對象用於通常用途。
  • public void onActivityCreated(Bundle savedInstanceState)
    在Activity的onCreate()方法執行完以後,Android系統會馬上調用該方法,表示Activity窗口已經初始化完成,從這一個時候開始,就能夠在Fragment中使用getActivity().findViewById(R.id.xxx);來操做Activity中的view了。
  • public void onStart()
    這個沒啥可講的,可是一個細節須要知道,當系統調用該方法的時候,fragment已經顯示在UI上了,但還不能進行互動,由於onResume()方法尚未執行完。
  • public void onResume()
    該方法爲fragment從建立到顯示Android系統調用的最後一個生命週期方法,調用完該方法時候,fragment就能夠與用戶互動了。
  • public void onPause()
    fragment由活動狀態變成非活躍執行的第一個回調方法,一般能夠在這個方法中保存一些須要臨時暫停的工做。例如:存音樂播放速度,而後在onResume()方法中恢復音樂播放進度。
  • public void onStop()
    當onStop()返回的時候,fragment將從屏幕上消失。
  • public void onDestoryView()
    該方法的調用意味着在onCreateView()中建立的視圖都將被移除。
  • public void onDestroy()
    Android在Fragment再也不使用時會調用該方法,要注意的是~這是Fragment還和Activity是藕斷絲連!而且能夠得到Fragment對象,但沒法對得到的Fragment進行任何操做。
  • public void onDetach()
    爲Fragment生命週期中的最後一個方法,當該方法執行完後,Fragment與Activity再也不有關聯。

Fragment比Activity多了幾個額外的生命週期回調方法:.net

  • onAttach(Activity):當Fragment和Activity發生關聯時使用。
  • onCreateView(LayoutInflater,ViewGroup,Bundle):建立該Fragment的視圖
  • onActivityCreate(Bundle):當Activity的onCreate()方法返回時調用
  • onDestoryView():與onCreateView相對應,當該Fragment的視圖被移除時調用
  • onDetach():與onAttach()相對應,當Fragment與Activity關聯被取消時調用
    注意:除了onCreateView()方法,其餘的全部的方法若是你重寫了,必須調用父類對於該方法的實現

管理fragment生命週期與管理activity生命週期很相像

像activity同樣,fragment也有三種狀態:

  • Resumed
    fragment在運行中的activity中可見
  • Paused
    另外一個activity處於前臺且獲得焦點,可是這個fragment所在的activtiy仍然可見(前臺activity部分透明,或者沒有覆蓋全屏)。
  • Stopped
    fragment不可見。要麼宿主activity已經中止,要麼fragment已經從activity上移除,但已被添加到後臺棧中。一箇中止的fragment仍然活着(全部的狀態和成員信息仍然由系統保留着)。可是,它對於用戶來說已經再也不可見,而且若是activity被殺掉,它也將被殺掉。
    ————————————————————————————————
    若是activity的進程被殺掉了,在activity被從新建立時,你恢復fragment狀態。能夠執行fragment的onSaveIntanceState()來保存狀態(注意:fragment是在onCreate(),onCreateView()或者onActivityCreate()中進行恢復)
    在生命週期方面,activity和fragment之間一個很重要的不一樣就是在各自的後臺棧中是如何存儲的。當activity中止時,默認狀況下activity被安置在由系統管理的activity後臺棧中;fragment僅當在一個事務被移除時,經過顯式調用addToBackStack()請求保存的實例,該fragment才被置於由宿主activity管理的後臺棧。
    要建立一個fragment,必須建立一個fragment的子類,通常狀況下,咱們至少須要實現如下幾個fragment生命週期的方法:onCreate(),onCreateView(),onPause()

 

@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);
  }```
inflate()函數須要如下三個參數:
(1).要inflate的佈局的資源Id
(2).被inflate的佈局的父ViewGroup
(3).一個布爾值,代表在inflate期間被inflate的佈局是否應該附上ViewGroup(第二個參數container)。(在這個例子中傳入的是false,由於系統已經將被inflate的佈局插入到容器中(container)——傳入true會在最終的佈局裏建立一個多餘的ViewGroup)

#####Fragment與Activity之間的交互:
* 將Fragment添加到activity之中
能夠經過在activtiy佈局文件中聲明fragment,用fragment標籤把fragment插入到activity的佈局中,或者是用應用程序源碼將它添加到一個存在的ViewGroup中。但fragment並非必定要做爲activity佈局的一部分,fragment也能夠爲activity隱身工做。
**(1).在activity的佈局文件裏聲明fragment**
能夠像view同樣爲fragment指定佈局屬性。代碼以下:

 

<?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.test.FragmentOne"
            android:id="@+id/fo"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
</LinearLayout>

 

fragment標籤中的android:name屬性指定了佈局中實例化Fragment類。
當系統建立activity佈局時,它實例化了佈局文件中指定的每個fragment,併爲它們調用onCeateView()函數,以獲取每個fragment的佈局。系統直接在元素的位置插入fragment返回的View。
**注意:每一個fragment都須要一個惟一的標識,若是重啓activity,系統可用來恢復fragment(而且可用來捕捉fragment的事務處理,例如:移除fragment),爲fragment提供了ID有三種方法:**
1:>用android:id屬性提供一個惟一的標識
2:>用android:tag屬性提供一個惟一的字符串。
3:>若是上述兩種屬性都沒有,系統會使用其容器視圖(view)的ID。
**(2).經過編碼將fragment添加到已存在的ViewGroup中**
在activity運行的任什麼時候候,你均可以將fragment添加到activity佈局中。要管理activity中的fragment,可使用FragmentManager。能夠經過在activity中調用getFragmentManager()得到。使用FragmentManager能夠作以下事情,包括:
1:>使用findFragmentById()(用於在activity佈局中提供有界面的fragment或者findFragmentByTag()獲取activity中存在的fragment(用於有界面或者沒有界面的fragment))
2:>使用popBackStack()(模仿用戶的Back命令)從後臺棧彈出fragment。
3:>使用addOnBackStackChangeListener()註冊一個監聽後臺棧變化的監聽器。
在android中,對fragment的事務操做都是經過FragmentTranSaction來執行。操做大體能夠分爲兩類:
1:>顯示:add(), replace(), show(), attach()
2:>隱藏:remove(), hide(), detach()
**說明**:調用show() & hide()方法時,Fragment的生命週期方法並不會被執行,僅僅是Fragment的View被顯示或者​隱藏。執行replace()時(至少兩個Fragment),會執行第二個Fragment的onAttach()方法、執行第一個Fragment的onPause()-onDetach()方法,同時containerView會detach第一個Fragment的View。add()方法執行onAttach()-onResume()的生命週期,相對的remove()就是執行完成剩下的onPause()-onDetach()週期。
能夠像下面這樣從Activity中取得FragmentTransaction的實例:

FragmentManager fragmentManager = getFragmentManager() 
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();```
能夠用add()函數添加fragment,並指定要添加的fragment以及要將其插入到哪一個視圖(view)之中(注意commit事務):

 

ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();```
**(3).添加沒有界面的fragment**
也可使用fragment爲activity提供後臺動做,卻不呈現多餘的用戶界面。想要添加沒有界面的fragment ,可使用add(Fragment, String)(爲fragment提供一個惟一的字符串「tag」,而不是視圖(view)ID)。這樣添加了fragment,可是,由於尚未關聯到activity佈局中的視圖(view) ,收不到onCreateView()的調用。因此不須要實現這個方法。對於無界面fragment,字符串標籤是惟一識別它的方法。若是以後想從activity中取到fragment,須要使用findFragmentByTag()。 

* Fragment與Activity之間的交互能夠經過Fragment.setArguments(Bundle args)以及Fragment.getArguments()來實現。

#####Fragment狀態的持久化:
因爲Activity會常常性的發生配置變化,因此依附它的Fragment就有須要將其狀態保存起來問題。下面有兩種經常使用的方法去將Fragment的狀態持久化。
* 方法一
能夠經過```protected void onSaveInstanceState(Bundle outState),protected void onRestoreInstanceState(Bundle savedInstanceState)```狀態保存和恢復的方法將狀態持久化。
* 方法二(更爲方便,讓Android自動幫咱們保存Fragment狀態)
**<1>.**咱們只須要將Fragment在Activity中做爲一個變量整個保存,只要保存了Fragment,那麼Fragment的狀態就獲得保存了,因此咱們就能夠經過下面方法,進行獲取Fragment數據。

FragmentManager.putFragment(Bundle bundle, String key, Fragment
fragment) 是在Activity中保存Fragment的方法。
FragmentManager.getFragment(Bundle bundle, String key)
是在Activity中獲取所保存的Frament的方法。```
<2>.很顯然,上述<1>中的key就傳入Fragment的id,fragment就是你要保存狀態的fragment,但,咱們注意到上面的兩個方法,第一個參數都是Bundle,這就意味着FragmentManager是經過Bundle去保存Fragment的。可是,這個方法僅僅可以保存Fragment中的控件狀態,好比說:EditText中用戶已經輸入的文字(注意:在這裏,控件須要設置一個id值,不然Android將不會爲咱們保存該控件的狀態),而Fragment中須要持久化的變量依然會丟失,但依然有解決方法,就是利用方法一!
<3>.下面給出狀態的持久化實例代碼:

 

/** Activity中的代碼 **/
    FragmentB fragmentB;

   @Override
   protected void onCreate(@Nullable Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.fragment_activity);
       if( savedInstanceState != null ){
           fragmentB = (FragmentB) getSupportFragmentManager()
                       .getFragment(savedInstanceState,"fragmentB");
       }
       init();
   }

   @Override
   protected void onSaveInstanceState(Bundle outState) {
       if( fragmentB != null ){
          getSupportFragmentManager()
            .putFragment(outState,"fragmentB",fragmentB);
       }
       super.onSaveInstanceState(outState);
   }

   /** Fragment中保存變量的代碼 **/
   @Nullable
   @Override
   public View onCreateView(LayoutInflater inflater, @Nullable 
       ViewGroup container, @Nullable Bundle savedInstanceState) {
       AppLog.e("onCreateView");
       if ( null != savedInstanceState ){
           String savedString = savedInstanceState
                                .getString("string");
           //獲得保存下來的string
       }
       View root = inflater.inflate(R.layout.fragment_a,null);
       return root;
   }

   @Override
   public void onSaveInstanceState(Bundle outState) {
       outState.putString("string","anAngryAnt");
       super.onSaveInstanceState(outState);
   }

靜態的使用Fragment

1.集成Fragment,重寫onCreateView()決定Fragment的佈局
2.在Activity中聲明此Fragment,就和普通的View同樣。

Fragment經常使用的API

  • android.support.v4.app.Fragment:主要用於定義Fragment
  • android.support.v4.app.FragmentManager :主要用於在Activity中操做Fragment,可使用FragmentMagager.findFragmentById()和FragmentMagager.findFragmentByTag()等方法去找到一個Fragment
  • android.support.v4.app.FragmentTransaction:保證一些Fragment操做的原子性,熟悉事務這個詞。
  • 主要的操做都是FragmentTransaction的方法(通常咱們爲了向下兼容,都會使用support.v4包裏面的Fragment)
    getFragmentManager() //Fragment若使用的是support.v4包中的,那就使用getSupportFragmentManager代替

連接:關於getChildFragmentManager()、 getFragmentManager()、getSupportFragmentManager()的使用

  • 主要的操做都是FragmentTransaction的方法:

 

FragmentTransaction transaction = fm.benginTransatcion();//開啓一個事務
    //往Activity中添加一個Fragment
    transaction.add() 

    transaction.remove() 
    //從Activity中移除一個Fragment,若是被移除的Fragment沒有添    加到回退棧
     (回退棧後面會詳細說),這個Fragment實例將會被銷燬。

    transaction.replace()
    //使用另外一個Fragment替換當前的,實際上就是remove()而後add()的合體~

    transaction.hide()
    //隱藏當前的Fragment,僅僅是設爲不可見,並不會銷燬

    transaction.show()
    //顯示以前隱藏的Fragment

    detach()
    //當fragment被加入到回退棧的時候,該方法與*remove()*的做用是相同的,
    //反之,該方法只是將fragment從視圖中移除,
    //以後仍然能夠經過*attach()*方法從新使用fragment,
    //而調用了*remove()*方法以後,
    //不只將Fragment從視圖中移除,fragment還將再也不可用。

    attach()
    //重建view視圖,附加到UI上並顯示。

    transatcion.commit()
    //提交一個事務

在調用commit()以前,能夠將事務添加到fragment事務後臺棧中(經過調用addToBackStatck())。這個後臺棧由activity管理,而且容許用戶經過按BACK鍵回退到前一個fragment狀態。
下面的代碼中一個fragment代替另外一個fragment,而且將以前的fragment狀態保留在後臺棧中:

 

Fragment newFragment = new ExampleFragment();
 FragmentTransaction transaction = getFragmentManager().beginTransaction();
 transaction.replace(R.id.fragment_container, newFragment);
 transaction.addToBackStack(null);
 transaction.commit();```
**注意**:
若是添加多個變動事務(例如另外一個add()或者remove())並調用addToBackStack(),那麼在調用commit()以前的全部應用的變動被做爲一個單獨的事務添加到後臺棧中,而且BACK鍵能夠將它們一塊兒回退。
當移除一個fragment時,若是調用了addToBackStack(),那麼以後fragment會被中止,若是用戶回退,它將被恢復過來。
調用commit()並不馬上執行事務,相反,而是採起預定方式,一旦activity的界面線程(主線程)準備好即可運行起來。然而,若是有必要的話,你能夠從界面線程調用executePendingTransations()當即執行由commit()提交的事務。
只能在activity保存狀態(當用戶離開activity時)以前用commit()提交事務。若是你嘗試在那時以後提交,會拋出一個異常。這是由於若是activity須要被恢復,提交後的狀態會被丟失。對於這類丟失提交的狀況,可以使用commitAllowingStateLoss()

#####管理Fragment回退棧
* 跟蹤回退棧的狀態
咱們經過實現```OnBackStackChangedListener```接口來實現回退棧狀態跟蹤,具體代碼以下:

//implements接口
public class XXX implements FragmentManager.OnBackStackChangedListener
//實現接口所要實現的方法
@Override
public void onBackStackChanged() {
//do whatevery you want
}
//設置回退棧監聽接口
getSupportFragmentManager().addOnBackStackChangedListener(this);

 

* 管理回退棧
**(1).```FragmentTransaction.addToBackStack(String)```**
將一個剛剛添加的Fragment加入到回退棧中
**(2).```getSupportFragmentManager().getBackStackEntryCount()```**
獲取回退棧中的實體數量
**(3).```getSupportFragmentManager().popBackStack(String name, int flags)```**
根據name馬上彈出棧頂的fragment
**(4).```getSupportFragmentManager().popBackStack(int id, int flags)```**
根據id馬上彈出棧頂的fragment

**結束語:相信本身,必定能夠成爲本身想成爲的那我的的,加油!   ---王令
QQ:2585085940
郵箱:wang91ling@163.com
歡迎你們光臨寒舍。**

做者:wangling90 連接:https://www.jianshu.com/p/94bede7d6f46 來源:簡書 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

相關文章
相關標籤/搜索