天天看點

FragmentManager與FragmentTransaction1. FragmentManager簡介2. FragmentManager的擷取3. FragmentTransaction簡介4. FragmentTransaction的擷取5. 二者結合的典型用法6. 擷取某個已添加的Fragment7. 支援多個Fragment背景棧8. 總結

文章目錄

  • 1. FragmentManager簡介
  • 2. FragmentManager的擷取
    • 2.1 從Activity中擷取FragmentManager
    • 2.2 從Fragment上擷取FragmentManager
  • 3. FragmentTransaction簡介
  • 4. FragmentTransaction的擷取
  • 5. 二者結合的典型用法
  • 6. 擷取某個已添加的Fragment
    • 6.1 findFragmentById
    • 6.2 findFragmentByTag
  • 7. 支援多個Fragment背景棧
  • 8. 總結

1. FragmentManager簡介

FragmentManager,顧名思義是負責管理Fragment的管理類,可以對Fragment進行添加、移除、替換等操作。并且,Fragment也有和Activity類似的任務棧。Fragment可被添加到棧中,也可以出棧。

2. FragmentManager的擷取

2.1 從Activity中擷取FragmentManager

從前面的章節我們了解到,Fragment是依附在Activity上的子頁面。那麼負責管理這些子頁面的FragmentManager自然可從Activity上擷取了。隻不過這種Activity比較特殊,是一種FragmentActivity。

  • ApppCompatActivity、FragmentActivity、Activity三者的繼承關系是: ApppCompatActivity繼承自FragmentActivity,FragmentActivity繼承自Activity

    是以,FragmentActivity或者是繼承自FragmentActivity的子類(比如,ApppCompatActivity)都可以獲得FragmentManager。擷取方法是:

    getSupportFragmentManager()

    。從support可以看出,這裡擷取的是具有相容性的Fragment,也就是Android Support或者AndroidX包裡面的Fragment。
  • 注意,不要用老舊的

    android.app.fragment

    ,

    getFragmentManager()

    ,已不推薦使用。

2.2 從Fragment上擷取FragmentManager

Fragment除了依附在Activity上,也可以依附在别Fragmet上。這時被依附的Fragment就是父Fragment,依附的Fragment就是子Fragment。

那麼管理子Fragment的FragmentManager自然可以從其父Fragment裡擷取。方法是:

getChildFragmentManager()

。也好了解,管理子Fragment嘛,自然是getChildFragmentManager。

上面是一個Fragment擷取其子Fragment的管理類(

getChildFragmentManager()

),而要想擷取管理自身的管理類,可以通過

getParentFragmentManager()

方法實作。

Fragment與其持有者(Activity或父Fragment),還有FragmentManager的對應關系可用下圖表示:

FragmentManager與FragmentTransaction1. FragmentManager簡介2. FragmentManager的擷取3. FragmentTransaction簡介4. FragmentTransaction的擷取5. 二者結合的典型用法6. 擷取某個已添加的Fragment7. 支援多個Fragment背景棧8. 總結

3. FragmentTransaction簡介

FragmentManager是Fragment的管理者,但它還需要一個助手幫它完成Fragment的add、replace等操作。這個助手就是FragmentTransaction。

對Fragment的添加、替換等操作可能會有多個。比如先移除目前FragmentA,再添加FragmentB,這樣兩個操作通常就被打包一次Transaction,統一送出(commit)。比如下面的代碼:

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
	.remove(fragmentA)
	.add(R.id.fragment_container, FragmentB.class,null)
    .setReorderingAllowed(true)
    .addToBackStack("name") // name can be null
    .commit();
           
  • Transaction,是事務的意思,原本是資料庫中的概念。引申到這裡,可了解為把多個操作打包為整體,統一送出。如果其中某個操作失敗了,那麼整個操作全部恢複到操作之前。這樣可以保證操作的完整性。
  • 舉個例子,A向B轉賬100元的操作可簡化為以下幾步:1.A的賬戶錢數減100; 2. B的賬戶加100。假如操作1執行完,操作2執行失敗了,那麼整個轉賬操作應該認為是失敗的,應該回退到轉賬之前。這時候“事務”的操作就發揮作用了。根據“事務”的概念,1和2應該是一個整體,2失敗了,那麼所有操作恢複到操作之前。是以,“操作1. A的賬戶錢數減100”,就會回退到之前,即再加100恢複到原數目,進而保證了資料的完整性。

4. FragmentTransaction的擷取

從上面代碼可以看出FragmentTransaction是FragmentManager的助手,自然會通過FragmentManager獲得。如下代碼:

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction()
           

5. 二者結合的典型用法

了解了FragmentManager以及FragmentTransaction後,我們來看二者結合後常見的操作,比如将一個Fragment添加到某個FragmentContainer上。

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .replace(R.id.fragment_container, ExampleFragment.class, null)
    .setReorderingAllowed(true)
    .addToBackStack("name") // name can be null
    .commit();
           

這裡值得注意的有以下幾點:

  1. 使用ExampleFragment.class而不是某個ExampleFragment對象,原因上節已經解釋過
  2. 添加setReorderingAllowed(true),原因仍參見上節
  3. addToBackStack(“name”),将本次操作整體添加到一個背景棧裡。當使用者點選傳回鍵時,就能依次彈出,當彈到棧為空,時再按傳回鍵,事件就會傳遞到所在Activity,執行其任務棧的回退。
  4. 如果不加addToBackStack,當你移除一個Fragment後,該Fragment會被銷毀,無法再跳到該Fragment。而加了addToBackStack後,Fragment被移除後,該Fragment隻是切換到了Stop狀态,仍然有機會再跳轉到該Fragment。

6. 擷取某個已添加的Fragment

Fragment被添加後,有兩種方式擷取已添加的Fragment對象。

  • findFragmentById
  • findFragmentByTag

6.1 findFragmentById

通過被添加到的容器的id擷取,該容器上目前的Fragment執行個體。

代碼舉例如下:

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .replace(R.id.fragment_container, ExampleFragment.class, null)
    .setReorderingAllowed(true)
    .addToBackStack(null)
    .commit();

ExampleFragment fragment =
        (ExampleFragment) fragmentManager.findFragmentById(R.id.fragment_container);
           

6.2 findFragmentByTag

Fragment添加的時候,可以為其加上一個Tag作為标簽。這樣後面就可以根據該标簽找到它了。

代碼舉例如下:

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .replace(R.id.fragment_container, ExampleFragment.class, null, "tag")
    .setReorderingAllowed(true)
    .addToBackStack(null)
    .commit();

ExampleFragment fragment = (ExampleFragment) fragmentManager.findFragmentByTag("tag");
           

7. 支援多個Fragment背景棧

有時我們需要同時操作多個Fragment棧。比如,底部導航菜單+多個Fragment頁面。通過FragmentManager,我們可以暫存某個棧,顯示另一個棧。對應的方法分别是

saveBackStack()

restoreBackStack()

代碼舉例如下:

首先,将Fragment添加到棧

supportFragmentManager.beginTransaction()
  .replace(R.id.fragment_container, ExampleFragment.class, null)
  .setReorderingAllowed(true)
  .addToBackStack("replacement")
  .commit();
           
注意,這裡的

setReorderingAllowed(true)

addToBackStack

是必須的。這樣才能使用saveBackStack和restoreBackStack。

接着,暫存Fragment棧:

然後,恢複Fragment棧:

8. 總結

本章節介紹了FragmentManager與FragmentTransaction的概念和用法,以及如何擷取某個已添加的Fragment,還涉及了對Fragment背景棧的了解。