Fragment新功能,setMaxLifecycle瞭解一下

HitenDev發表於2019-05-15

前言

寫上一篇ViewPager2軟文時,我發現最新的Fragment程式碼淘汰了setUserVisibleHint方法,轉而支援用setMaxLifecycle方法,setMaxLifecycle言外之意是設定最大生命週期,懂行的人應該知道,Fragment一直都是無法直接設定生命週期,必須通過addattachremovedetachshowhide方法間接干預,本來就此功能,簡單介紹一下setMaxLifecycle的原理和上手效果;

閱讀指南:

  • 本文基於androidx 1.1.0-alpha07版本的fragment進行,也是支援setMaxLifecycle的最低版本
  • 本文會根據FragmentPagerAdapter進行setMaxLifecycle示例應用講解

基本介紹

setMaxLifecycle定義在FragmentTransaction中,和之前的addattachremovedetachshowhide等方法是並列關係;

FragmentTransaction

public FragmentTransaction setMaxLifecycle(@NonNull Fragment fragment,
        @NonNull Lifecycle.State state) {
    addOp(new Op(OP_SET_MAX_LIFECYCLE, fragment, state));
    return this;
}
複製程式碼

引數解讀:

  • fragment 即需要操作的Fragment物件,前提條件是這個fragment必須已經加到FragmentManager中;
  • state Lifecycle.State列舉型別,該引數的使用條件是至少是Lifecycle.State.CREATED,否則報IllegalArgumentException異常

Lifecycle.State一共有五個狀態,最低要求是Lifecycle.State.CREATED,所以該方法可用的引數有CREATEDSTARTEDRESUMEDState生命週期方法有何區別,下面簡單解釋一下:

生命週期狀態理解

在Fragment中,定義了五種State,這裡的State並非上面說Lifecycle.State,但是邏輯基本上是一致的;

  • INITIALIZING 初始狀態
  • CREATED 已建立狀態
  • ACTIVITY_CREATED 完全建立,但是沒有started
  • STARTED 建立並啟動,可見不可操作
  • RESUMED 建立啟動並可操作
    Fragment新功能,setMaxLifecycle瞭解一下

本文內容只對CREATEDSTARTEDRESUMED這三個狀態講解,由於Fragment中定義的mStateLifecycle.State不是同一狀態,在本文視為同一概念;

與生命週期對應關係

各位肯定都知道Fragment生命週期有onDestoryonStop等方法,但是狀態卻沒有這麼多,那麼如何標識狀態和對應關係,下面給出對應關係;

首先,我把生命週期方法從onCreate->onCretateView->onStart->onResume->onPause->onStop-> onDestoryView->onDestory視為從小到大排序;

同樣的,我們把生命週期狀態CREATED->STARTED->RESUMED視為從小到大排序;

  • CREATED狀態

CREATED即已建立狀態,狹義的理解是生命週期方法走到onCreate,如果當前fragment狀態已大於CREATED,則會使fragment生命週期方法走到onDestoryView,如果小於CREATED,則走到onCreate;所以CREATED有兩種情況;

  • STARTED狀態

同理,STARTED狀態也有兩種情況,如果當前fragment狀態已大於STARTED,則會使fragment生命週期方法走到onPause,如果小於CREATED,則走到onStart

  • RESUMED狀態

RESUMED表示的狀態比較特殊,只代表onResume狀態,無論大到小還是小到大,最終都是停留到onResume狀態;

以上生命週期狀態扭轉結論基於FragmentManagerImpl.moveToState()方法提取,如有誤導,請指教

如何使用

setMaxLifecycle可以單獨使用,也可以配合add等方法組合使用,首先,我們分析單獨執行add命令的狀態變化:

單獨執行add操作

FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.frame_layout,cardFragment);
fragmentTransaction.commit();
複製程式碼

Fragment新功能,setMaxLifecycle瞭解一下

add配合setMaxLifecycle(Lifecycle.State.CREATED)

FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.frame_layout,cardFragment);
fragmentTransaction.setMaxLifecycle(cardFragment, Lifecycle.State.CREATED);
fragmentTransaction.commit();
複製程式碼

Fragment新功能,setMaxLifecycle瞭解一下

add配合setMaxLifecycle(Lifecycle.State.STARTED)

FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.frame_layout,cardFragment);
fragmentTransaction.setMaxLifecycle(cardFragment, Lifecycle.State.STARTED);
fragmentTransaction.commit();
複製程式碼

Fragment新功能,setMaxLifecycle瞭解一下

add配合setMaxLifecycle(Lifecycle.State.RESUMED)

FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.frame_layout,cardFragment);
fragmentTransaction.setMaxLifecycle(cardFragment, Lifecycle.State.RESUMED);
fragmentTransaction.commit();
複製程式碼

Fragment新功能,setMaxLifecycle瞭解一下

單獨使用setMaxLifecycle

FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setMaxLifecycle(cardFragment, xxx);
fragmentTransaction.commit();
複製程式碼
  • RESUMED狀態的Fragment進行操作CREATED操作

Fragment新功能,setMaxLifecycle瞭解一下

  • RESUMED狀態的Fragment進行操作STARTED操作

Fragment新功能,setMaxLifecycle瞭解一下

  • RESUMED狀態的Fragment進行操作CREATED操作,在進行STARTED操作

Fragment新功能,setMaxLifecycle瞭解一下

由於篇幅原因,就不一一介紹各種組合情況,只要弄清楚生命週期狀態,不論是狀態是升還是降,不論組合還是單用,你都可以駕馭;

FragmentPagerAdapter變動

由於setMaxLifecycle帶來了生命週期設定,替換掉了老舊的setUserVisibleHint方法,所以在FragmentPagerAdapter中也進行了適配

FragmentPagerAdapter

public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0;
public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1;

private final int mBehavior;

public FragmentPagerAdapter(@NonNull FragmentManager fm) {
    this(fm, BEHAVIOR_SET_USER_VISIBLE_HINT);
}

public FragmentPagerAdapter(@NonNull FragmentManager fm,@Behavior int behavior) {
    mFragmentManager = fm;
    mBehavior = behavior;
}
複製程式碼

最新的FragmentPagerAdapter用一個mBehavior來控制setUserVisibleHintsetMaxLifecycle二選一的局面; mBehavior在構造方法中指定;

Fragment新功能,setMaxLifecycle瞭解一下

從程式碼可以看出,用setMaxLifecycle(mCurrentPrimaryItem, Lifecycle.State.STARTED)替代setUserVisibleHint(false),用setMaxLifecycle(fragment, Lifecycle.State.RESUMED)替代setUserVisibleHint(true)

為什麼要用Lifecycle.State.STARTED?因為這裡本質上用的是add+Lifecycle.State.STARTEDattach+Lifecycle.State.STARTED組合;

最終的結果是不可見的Fragment只會走到生命週期onStart方法,不會走onResume方法;

懶載入新方案

綜上,過去使用setUserVisibleHint來控制Fragment懶載入,在最新版的FragmentPagerAdapter裡有新思路,可以切換到BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT模式,在FragmentonResume裡判斷,更符合顯示邏輯;

切換到BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT模式,需要呼叫倆引數的構造方法:

new FragmentPagerAdapter(getSupportFragmentManager(),FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)
複製程式碼

總結

破事水了小半天,本文到底說了什麼內容,還是做個總結吧:

首先使用setMaxLifecycle能進一步的控制Fragment生命週期,一句話形容就是對addattach等命令的補充;

其次該功能在官方控制元件中得以運用,改善了ViewPager+Fragment的使用體驗,懶載入注意點;

最後鼓勵大家(主要是自己)多看原始碼,夯實基礎,方能不變應萬變,本文結束。

相關文章