[Android] Fragment 全解析

來源:互聯網
上載者:User

標籤:

1.概述

  Fragment是Activity中使用者介面的一個行為或者是一部分。主要是支援在大螢幕上動態和更為靈活的去組合或是交換UI組件,通過將activity的布局分割成若干個fragment,可以在運行時編輯activity的呈現,並且那些變化會被儲存在由activity管理的後台棧裡面。

  Fragment必須總是被嵌入到一個activity之中,並且fragment的生命週期直接受其宿主activity的生命週期的影響。你可以認為fragment是activity的一個模組零件,它有自己的生命週期,接收它自己的輸入事件,並且可以在activity運行時添加或者刪除。

  應該將每一個fragment設計為模組化的和可複用化的activity組件。也就是說,你可以在多個activity中引用同一個fragment,因為fragment定義了它自己的布局,並且使用它本身生命週期回調的行為。

2.Fragment的生命週期

先看fragment生命週期圖:

  fragment所生存的activity生命週期直接影響著fragment的生命週期,由此針對activity的每一個生命週期回調都會引發一個fragment類似的回調。例如,當activity接收到onPause()時,這個activity之中的每個fragment都會接收到onPause()。
  這有Activity的詳細說明

  Fragment有一些額外的生命週期回調方法(建立和銷毀fragment介面).

  • onAttach()

      當fragment被綁定到activity時調用(Activity會被傳入)。

  • onCreateView()

      將本身的布局構建到activity中去(fragment作為activity介面的一部分)
      

  • onActivityCreated()

      當activity的onCreate()函數返回時被調用。

  • onDestroyView()

      當與fragment關聯的視圖體系正被移除時被調用。

  • onDetach()

      當fragment正與activity解除關聯時被調用。

當activity接收到它的onCreate()回調時,activity之中的fragment接收到onActivityCreated()回調。

  一旦activity處於resumed狀態,則可以在activity中自由的添加或者移除fragment。因此,只有當activity處於resumed狀態時,fragment的生命週期才可以獨立變化。
  
fragment會在 activity離開恢複狀態時 再一次被activity推入它的生命週期中。

管理fragment生命週期與管理activity生命週期很相像。像activity一樣,fragment也有三種狀態:

  • Resumed

      fragment在運行中的activity可見。

  • Paused

      另一個activity處於前台且得到焦點,但是這個fragment所在的activity仍然可見(前台activity部分透明,或者沒有覆蓋全屏)。

  • Stopped

      fragment不可見。要麼宿主activity已經停止,要麼fragment已經從activity上移除,但已被添加到後台棧中。一個停止的fragment仍然活著(所有狀態和成員資訊仍然由系統保留著)。但是,它對使用者來講已經不再可見,並且如果activity被殺掉,它也將被殺掉。

      如果activity的進程被殺掉了,在activity被重新建立時,你需要恢複fragment狀態。可以執行fragment的onSaveInstanceState()來儲存狀態(注意在fragment是在onCreate(),onCreateView(),或onActvityCreate()中進行恢複)。

      在生命週期方面,activity與fragment之間一個很重要的不同,就是在各自的後台棧中是如何儲存的。
      當activity停止時,預設情況下activity被安置在由系統管理的activity後台棧中; 
      fragment僅當在一個事務被移除時,通過顯式調用addToBackStack()請求儲存的執行個體,該fragment才被置於由宿主activity管理的後台棧。 

要建立一個fragment,必須建立一個fragment的子類。一般情況下,我們至少需要實現以下幾個fragment生命週期方法:

onCreate()

  在建立fragment時系統會調用此方法。在實現代碼中,你可以初始化想要在fragment中保持的那些必要組件,當fragment處於暫停或者停止狀態之後可重新啟用它們。

onCreateView()

  在第一次為fragment繪製使用者介面時系統會調用此方法。為fragment繪製使用者介面,這個函數必須要返回所繪出的fragment的根View。如果fragment沒有使用者介面可以返回空。

@Override        public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {             // Inflate the layout for this fragmentreturn inflater.inflate(R.layout.example_fragment, container, false);        }

inflate()函數需要以下三個參數:

①要inflate的布局的資源ID。 

②被inflate的布局的父ViewGroup。

③一個布爾值,表明在inflate期間被infalte的布局是否應該附上ViewGroup(第二個參數container)。(在這個例子中傳入的是false,因為系統已經將被inflate的布局插入到容器中(container)——傳入true會在最終的布局裡建立一個多餘的ViewGroup。) 

onPause()

  系統回調用該函數作為使用者離開fragment的第一個預兆(儘管這並不總意味著fragment被銷毀)。在目前使用者會話結束之前,通常要在這裡提交任何應該持久化的變化(因為使用者可能不再返回)。

3.將fragment添加到activity之中

  可以通過在activity布局檔案中聲明fragment,用fragment標籤把fragment插入到activity的布局中,或者是用應用程式源碼將它添加到一個存在的ViewGroup中。 
  
  但fragment並不是一個定要作為activity布局的一部分,fragment也可以為activity隱藏工作。

3.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,並為它們調用onCreateView()函數,以擷取每一個fragment的布局。系統直接在元素的位置插入fragment返回的View。

  注意:每個fragment都需要一個唯一的標識,如果重啟activity,系統可用來恢複fragment(並且可用來捕捉fragment的交易處理,例如移除)。為fragment提供ID有三種方法:

  • 用android:id屬性提供一個唯一的標識。 

  • 用android:tag屬性提供一個唯一的字串。 

  • 如果上述兩個屬性都沒有,系統會使用其[內容] 檢視(view)的ID。 

3.2通過編碼將fragment添加到已存在的ViewGroup中

  在activity啟動並執行任何時候,你都可以將fragment添加到activity布局中。
  
  要管理activity中的fragment,可以使用FragmentManager。可以通過在activity中調用getFragmentManager()獲得。使用FragmentManager 可以做如下事情,包括:

  • 使用findFragmentById()(用於在activity布局中提供有介面的fragment)或者findFragmentByTag()擷取activity中存在的fragment(用於有介面或者沒有介面的fragment)。  

  • 使用popBackStack()(模仿使用者的BACK命令)從後台棧彈出fragment。  

  • 使用addOnBackStackChangedListener()註冊一個監聽後台棧變化的監聽器。

在Android中,對Fragment的事務操作都是通過FragmentTransaction來執行。操作大致可以分為兩類:

  • 顯示:add() replace() show() attach()  

  • 隱藏: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.3添加沒有介面的fragment

  也可以使用fragment為activity提供後台動作,卻不呈現多餘的使用者介面。

  想要添加沒有介面的fragment ,可以使用add(Fragment, String)(為fragment提供一個唯一的字串“tag”,而不是視圖(view)ID)。這樣添加了fragment,但是,因為還沒有關聯到activity布局中的視圖(view) ,收不到onCreateView()的調用。所以不需要實現這個方法。 
  
  對於無介面fragment,字串標籤是唯一識別它的方法。如果之後想從activity中取到fragment,需要使用findFragmentByTag()。 

4.fragment事務後台棧

  在調用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()

5.與Activity互動
  • Activity中已經有了該Fragment的引用,直接通過該引用進行互動。

    -如果沒引用可以通過調用fragment的函數findFragmentById()或者findFragmentByTag(),從FragmentManager中擷取Fragment的索引,例如:

ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
  • 在Fragment中可以通過getActivity得到當前綁定的Activity的執行個體。

  • 建立activity事件回呼函數,在fragment內部定義一個回調介面,宿主activity來實現它。

參考:

fragments API Guides

FragmentTransaction Reference

[Android] Fragment 全解析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.