前言
寫上一篇ViewPager2軟文時,我發現最新的Fragment
程式碼淘汰了setUserVisibleHint
方法,轉而支援用setMaxLifecycle
方法,setMaxLifecycle
言外之意是設定最大生命週期
,懂行的人應該知道,Fragment
一直都是無法直接設定生命週期,必須通過add
、attach
、remove
、detach
、show
、hide
方法間接干預,本來就此功能,簡單介紹一下setMaxLifecycle
的原理和上手效果;
閱讀指南:
- 本文基於
androidx 1.1.0-alpha07
版本的fragment
進行,也是支援setMaxLifecycle
的最低版本 - 本文會根據
FragmentPagerAdapter
進行setMaxLifecycle
示例應用講解
基本介紹
setMaxLifecycle
定義在FragmentTransaction
中,和之前的add
、attach
、remove
、detach
、show
、hide
等方法是並列關係;
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
,所以該方法可用的引數有CREATED
、STARTED
、RESUMED
,State
和生命週期方法
有何區別,下面簡單解釋一下:
生命週期狀態理解
在Fragment中,定義了五種State
,這裡的State
並非上面說Lifecycle.State
,但是邏輯基本上是一致的;
INITIALIZING
初始狀態CREATED
已建立狀態ACTIVITY_CREATED
完全建立,但是沒有startedSTARTED
建立並啟動,可見不可操作RESUMED
建立啟動並可操作
本文內容只對CREATED
、STARTED
、RESUMED
這三個狀態講解,由於Fragment中定義的mState
和Lifecycle.State
不是同一狀態,在本文視為同一概念;
與生命週期對應關係
各位肯定都知道Fragment生命週期有onDestory
,onStop
等方法,但是狀態卻沒有這麼多,那麼如何標識狀態和對應關係,下面給出對應關係;
首先,我把生命週期方法從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();
複製程式碼
add配合setMaxLifecycle(Lifecycle.State.CREATED)
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.frame_layout,cardFragment);
fragmentTransaction.setMaxLifecycle(cardFragment, Lifecycle.State.CREATED);
fragmentTransaction.commit();
複製程式碼
add配合setMaxLifecycle(Lifecycle.State.STARTED)
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.frame_layout,cardFragment);
fragmentTransaction.setMaxLifecycle(cardFragment, Lifecycle.State.STARTED);
fragmentTransaction.commit();
複製程式碼
add配合setMaxLifecycle(Lifecycle.State.RESUMED)
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.frame_layout,cardFragment);
fragmentTransaction.setMaxLifecycle(cardFragment, Lifecycle.State.RESUMED);
fragmentTransaction.commit();
複製程式碼
單獨使用setMaxLifecycle
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setMaxLifecycle(cardFragment, xxx);
fragmentTransaction.commit();
複製程式碼
- 對
RESUMED
狀態的Fragment進行操作CREATED
操作
- 對
RESUMED
狀態的Fragment進行操作STARTED
操作
- 對
RESUMED
狀態的Fragment進行操作CREATED
操作,在進行STARTED
操作
由於篇幅原因,就不一一介紹各種組合情況,只要弄清楚生命週期狀態,不論是狀態是升還是降,不論組合還是單用,你都可以駕馭;
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
來控制setUserVisibleHint
和setMaxLifecycle
二選一的局面;
mBehavior
在構造方法中指定;
從程式碼可以看出,用setMaxLifecycle(mCurrentPrimaryItem, Lifecycle.State.STARTED)
替代setUserVisibleHint(false)
,用setMaxLifecycle(fragment, Lifecycle.State.RESUMED)
替代setUserVisibleHint(true)
;
為什麼要用Lifecycle.State.STARTED
?因為這裡本質上用的是add
+Lifecycle.State.STARTED
和attach
+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
生命週期,一句話形容就是對add
、attach
等命令的補充;
其次該功能在官方控制元件中得以運用,改善了ViewPager
+Fragment
的使用體驗,懶載入注意點;
最後鼓勵大家(主要是自己)多看原始碼,夯實基礎,方能不變應萬變,本文結束。