Fragments (Android官方文檔中文版)

來源:互聯網
上載者:User

Fragment 表現 Activity 中用UI的一個行為或者一部分.可以組合多個fragment放在一個單獨的activity中來建立一個多介面地區的UI,並可以在多個activity裡重用某一個fragment.把fragment想象成一個activity的模組化地區, 有它自己的生命週期, 接收屬於它的輸入事件,並且可以在activity運行期間添加和刪除.

Fragment 必須總是被嵌入到一個activity中, 它們的生命週期直接被其所屬的宿主activity的生命週期影響.例如, 當activity被暫停,那麼在其中的所有fragment也被暫停; 當activity被銷毀,所有隸屬於它的fragment也被銷毀. 然而,當一個activity正在運行時(處於resumed狀態),我們可以獨立地操作每一個fragment, 比如添加或刪除它們. 當處理這樣一個fragment事務時,也可以將它添加到activity所管理的back stack -- 每一個activity中的backstack實體都是一個發生過的fragment事務的記錄.
back stack允許使用者通過按下 BACK按鍵從一個fragment事務後退(往後導航).

將一個fragment作為activity布局的一部分添加進來時, 它處在activity的viewhierarchy中的ViewGroup中,並且定義有它自己的view布局.通過在activity的布局檔案中聲明fragment來插入一個fragment到你的activity布局中,或者可以寫代碼將它添加到一個已存在的ViewGroup.然而, fragment並不一定必須是activity布局的一部分;也可以將一個fragment作為activity的隱藏的後台工作者.

本文檔描述了如何使用fragment建立你的應用程式, 包括:當被添加到activity的back stack後,fragment如何維護他們的狀態.在activity中,與activity和其他fragment共用事件.構建到activity的actionbar.以及更多內容.

設計哲學

Android在3.0中引入了fragments的概念,主要目的是用在大螢幕裝置上--例如平板電腦上,支援更加動態和靈活的UI設計.平板電腦的螢幕要比手機的大得多,有更多的空間來放更多的UI組件,並且這些組件之間會產生更多的互動.Fragment允許這樣的一種設計,而不需要你親自來管理viewhierarchy的複雜變化.
通過將activity的布局分散到fragment中, 你可以在運行時修改activity的外觀,並在由activity管理的back stack中儲存那些變化.

例如, 一個新聞應用可以在螢幕左側使用一個fragment來展示一個文章的列表,然後在螢幕右側使用另一個fragment來展示一篇文章 – 2個fragment並排顯示在相同的一個activity中,並且每一個fragment擁有它自己的一套生命週期回調方法,並且處理它們自己的使用者輸入事件. 因此, 取代使用一個activity來選擇一篇文章,而另一個activity來閱讀文章 的方式,使用者可以在相同的activity中選擇一篇文章並且閱讀, :

fragment在你的應用中應當是一個模組化和可重用的組件.即,因為fragment定義了它自己的布局, 以及通過使用它自己的生命週期回調方法定義了它自己的行為,你可以將fragment包含到多個activity中. 這點特別重要, 因為這允許你將你的使用者體驗適配到不同的螢幕尺寸.舉個例子,你可能會僅當在螢幕尺寸足夠大時,在一個activity中包含多個fragment,並且,當不屬於這種情況時,會啟動另一個單獨的,使用不同fragment的activity.

繼續之前那個新聞的例子 -- 當運行在一個特別大的螢幕時(例如平板電腦),app可以在Activity A中嵌入2個fragment.然而,在一個正常尺寸的螢幕(例如手機)上,沒有足夠的空間同時供2個fragment用, 因此, Activity A會僅包含文章列表的fragment, 而當使用者選擇一篇文章時, 它會啟動Activity B,它包含閱讀文章的fragment. 因此, 應用可以同時支援圖1中的2種設計模式.

建立Fragment


要建立一個fragment, 必須建立一個 Fragment 的子類 (或者繼承自一個已存在的它的子類). Fragment類的代碼看起來很像 Activity .它包含了和activity類似的回調方法, 例如 onCreate(), onStart(),onPause,
以及 onStop(). 事實上, 如果你準備將一個現成的Android應用轉換到使用fragment,你可能只需簡單的將代碼從你的activity的回呼函數分別移動到你的fragment的回調方法.

通常, 應當至少實現如下的生命週期方法:

  • onCreate()
    當建立fragment時, 系統調用此方法.
    在實現代碼中,應當初始化想要在fragment中保持的必要組件, 當fragment被暫停或者停止後可以恢複.
  • onCreateView()
    fragment第一次繪製它的使用者介面的時候, 系統會調用此方法. 為了繪製fragment的UI,此方法必須返回一個View, 這個view是你的fragment布局的根view. 如果fragment不提供UI, 可以返回null.
  • onPause()
    使用者將要離開fragment時,系統調用這個方法作為第一個指示(然而它不總是意味著fragment將被銷毀.) 在目前使用者會話結束之前,通常應當在這裡提交任何應該持久化的變化(因為使用者有可能不會返回).


大多數應用應當為每一個fragment實現至少這3個方法,但是還有一些其他回調方法你也應當用來去處理fragment生命週期的各種階段.全部的生命週期回調方法將會在後面章節 Handlingthe Fragment Lifecycle 中討論.

除了繼承基類 Fragment , 還有一些子類你可能會繼承:

  • DialogFragment
    顯示一個浮動的對話方塊.
    用這個類來建立一個對話方塊,是使用在Activity類的對話方塊工具方法之外的一個好的選擇,
    因為你可以將一個fragment對話方塊合并到activity管理的fragment back stack中,允許使用者返回到一個之前曾被摒棄的fragment.
  • ListFragment
    顯示一個由一個adapter(例如 SimpleCursorAdapter)管理的項目的列表, 類似於ListActivity.
    它提供一些方法來管理一個list view, 例如 onListItemClick()回調來處理點擊事件.
  • PreferenceFragment
    顯示一個 Preference對象的階層的列表, 類似於PreferenceActivity.
    這在為你的應用建立一個"設定"activity時有用處.

添加一個使用者介面

fragment通常用來作為一個activity的使用者介面的一部分,並將它的layout提供給activity.為了給一個fragment提供一個layout,你必須實現 onCreateView()回調方法, 當到了fragment繪製它自己的layout的時候,Android系統調用它.你的此方法的實現代碼必須返回一個你的fragment的layout的根view.

注意: 如果你的fragment是ListFragment的子類,它的預設實現是返回從onCreateView()返回一個ListView,所以一般情況下不必實現它.

從onCreateView()返回的View, 也可以從一個xmllayout資源檔中讀取並產生. 為了協助你這麼做, onCreateView() 提供了一個LayoutInflater 對象.

舉個例子, 這裡有一個Fragment的子類, 從檔案 example_fragment.xml 載入了一個layout:

  1. public static class ExampleFragment extends Fragment {
  2. @Override
  3. public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  4. // Inflate the layout for this fragment
  5. return inflater.inflate(R.layout.example_fragment, container, false);
  6. }
  7. }

複製代碼

傳入 onCreateView() 的 container 參數是你的fragmentlayout將被插入的父ViewGroup(來自activity的layout).savedInstanceState 參數是一個Bundle, 如果fragment是被恢複的,它提供關於fragment的之前的執行個體的資料,

inflate() 方法有3個參數:

  • 想要載入的layout的resource ID.
  • 載入的layout的父ViewGroup.
    傳入container是很重要的, 目的是為了讓系統接受所要載入的layout的根view的layout參數,
    由它將掛靠的父view指定.
  • 布爾值指示在載入期間, 展開的layout是否應當附著到ViewGroup (第二個參數).
    (在這個例子中, 指定了false, 因為系統已經把展開的layout插入到container –傳入true會在最後的layout中建立一個多餘的view group.)

將fragment添加到activity
通常地, fragment為宿主activity提供UI的一部分, 被作為activity的整個viewhierarchy的一部分被嵌入. 有2種方法你可以添加一個fragment到activitylayout:

在activity的layout檔案中聲明fragment
你可以像為View一樣, 為fragment指定layout屬性.
例子是一個有2個fragment的activity:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="horizontal"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent">
  6. <fragment android:name="com.example.news.ArticleListFragment"
  7. android:id="@+id/list"
  8. android:layout_weight="1"
  9. android:layout_width="0dp"
  10. android:layout_height="match_parent" />
  11. <fragment android:name="com.example.news.ArticleReaderFragment"
  12. android:id="@+id/viewer"
  13. android:layout_weight="2"
  14. android:layout_width="0dp"
  15. android:layout_height="match_parent" />
  16. </LinearLayout>

複製代碼

<fragment> 中的 android:name屬性指定了在layout中執行個體化的Fragment類.

當系統建立這個activity layout時,它執行個體化每一個在layout中指定的fragment,並調用每一個上的onCreateView()方法,來擷取每一個fragment的layout.系統將從fragment返回的 View直接插入到<fragment>元素所在的地方.

注意: 每一個fragment都需要一個唯一的標識,如果activity重啟,系統可以用來恢複fragment(並且你也可以用來捕獲fragment來處理事務,例如移除它.)

有3種方法來為一個fragment提供一個標識:

  • 為 android:id 屬性提供一個唯一ID.
  • 為 android:tag 屬性提供一個唯一字串.
  • 如果以上2個你都沒有提供, 系統使用容器view的ID.

撰寫代碼將fragment添加到一個已存在的ViewGroup.
當activity啟動並執行任何時候, 都可以將fragment添加到activitylayout.只需簡單的指定一個需要放置fragment的ViewGroup.為了在你的activity中操作fragment事務(例如添加,移除,或代替一個fragment),必須使用來自FragmentTransaction 的API.

可以按如下方法,從你的Activity取得一個 FragmentTransaction 的執行個體:

  1. FragmentManager fragmentManager = getFragmentManager();
  2. FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

複製代碼

  然後你可以使用 add() 方法添加一個fragment, 指定要添加的fragment, 和要插入的view.

  1. ExampleFragment fragment = new ExampleFragment();
  2. fragmentTransaction.add(R.id.fragment_container, fragment);
  3. fragmentTransaction.commit();

複製代碼

add()的第一個參數是fragment要放入的ViewGroup, 由resource ID指定,第二個參數是需要添加的fragment.一旦用FragmentTransaction做了改變,為了使改變生效,必須調用commit().

添加一個無UI的fragment

之前的例子展示了對UI的支援, 如何將一個fragment添加到activity. 然而,也可以使用fragment來為activity提供後台行為而不用展現額外的UI.

要添加一個無UI的fragment, 需要從activity使用 add(Fragment, String) 來添加fragment (為fragment提供一個唯一的字串"tag", 而不是一個view ID).這麼做添加了fragment,但因為它沒有關聯到一個activity layout中的一個view, 所以不會接收到onCreateView()調用.因此不必實現此方法.

為fragment提供一個字串tag並不是專門針對無UI的fragment的 –也可以提供字串tag給有UI的fragment – 但是如果fragment沒有UI,那麼這個tag是僅有的標識它的途徑.如果隨後你想從activity擷取這個fragment, 需要使用 findFragmentByTag().

管理Fragment

要在activity中管理fragment,需要使用FragmentManager. 通過調用activity的getFragmentManager()取得它的執行個體.

可以通過FragmentManager做一些事情, 包括:

  • 使用findFragmentById() (用於在activitylayout中提供一個UI的fragment)或findFragmentByTag()(適用於有或沒有UI的fragment)擷取activity中存在的fragment
  • 將fragment從後台堆棧中彈出, 使用 popBackStack() (類比使用者按下BACK 命令).
  • 使用addOnBackStackChangeListener()註冊一個監聽後台堆棧變化的listener.

處理Fragment事務

關於在activity中使用fragment的很強的一個特性是:根據使用者的互動情況,對fragment進行添加,移除,替換,以及執行其他動作.提交給activity的每一套變化被稱為一個事務,可以使用在 FragmentTransaction 中的 API 處理.我們也可以儲存每一個事務到一個activity管理的backstack,允許使用者經由fragment的變化往回導航(類似於通過activity往後導航).

從 FragmentManager 獲得一個FragmentTransaction的執行個體 :

  1. FragmentManager fragmentManager = getFragmentManager();
  2. FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

複製代碼

每一個事務都是同時要執行的一套變化.可以在一個給定的事務中設定你想執行的所有變化,使用諸如 add(), remove(),和 replace().然後, 要給activity應用事務, 必須調用 commit().

  在調用commit()之前, 你可能想調用 addToBackStack(),將事務添加到一個fragment事務的backstack. 這個back stack由activity管理, 並允許使用者通過按下 BACK按鍵返回到前一個fragment狀態.

舉個例子, 這裡是如何將一個fragment替換為另一個, 並在後台堆棧中保留之前的狀態:

  1. // Create new fragment and transaction
  2. Fragment newFragment = new ExampleFragment();
  3. FragmentTransaction transaction = getFragmentManager().beginTransaction();
  4. // Replace whatever is in the fragment_container view with this fragment,
  5. // and add the transaction to the back stack
  6. transaction.replace(R.id.fragment_container, newFragment);
  7. transaction.addToBackStack(null);
  8. // Commit the transaction
  9. transaction.commit();

複製代碼

在這個例子中, newFragment替換了當前layout容器中的由R.id.fragment_container標識的fragment.通過調用addToBackStack(), replace事務被儲存到back stack,因此使用者可以回退事務,並通過按下BACK按鍵帶回前一個fragment.

如果添加多個變化到事務(例如add()或remove())並調用addToBackStack(),然後在你調用commit()之前的所有應用的變化會被作為一個單個事務添加到後台堆棧, BACK按鍵會將它們一起回退.

添加變化到 FragmentTransaction的順序不重要, 除以下例外:

  • 必須最後調用 commit().
  • 如果添加多個fragment到同一個容器, 那麼添加的順序決定了它們在view hierarchy中顯示的順序.

當執行一個移除fragment的事務時, 如果沒有調用 addToBackStack(), 那麼當事務提交後,那個fragment會被銷毀,並且使用者不能導航回到它. 有鑒於此, 當移除一個fragment時,如果調用了addToBackStack(), 那麼fragment會被停止, 如果使用者導航回來,它將會被恢複.

提示: 對於每一個fragment事務, 你可以應用一個事務動畫,通過在提交事務之前調用setTransition()實現.

調用 commit() 並不立即執行事務.恰恰相反, 它將事務安排排期, 一旦準備好,就在activity的UI線程上運行(主線程).如果有必要, 無論如何, 你可以從你的UI線程調用executePendingTransactions()來立即執行由commit()提交的事務. 但這麼做通常不必要,除非事務是其他線程中的job的一個從屬.

警告:你只能在activity儲存它的狀態(當使用者離開activity)之前使用commit()提交事務.

如果你試圖在那個點之後提交, 會拋出一個異常.這是因為如果activity需要被恢複,提交之後的狀態可能會丟失.對於你覺得可以丟失提交的狀況, 使用 commitAllowingStateLoss().

與Activity通訊

儘管Fragment被實現為一個獨立於Activity的對象,並且可以在多個activity中使用,但一個給定的fragment執行個體是直接綁定到包含它的activity的. 特別的,fragment可以使用 getActivity() 訪問Activity執行個體, 並且容易地執行比如在activitylayout中尋找一個view的任務.

  1. View listView = getActivity().findViewById(R.id.list);

複製代碼

同樣地,activity可以通過從FragmentManager獲得一個到Fragment的引用來調用fragment中的方法, 使用findFragmentById() 或 findFragmentByTag().

  1. ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_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.