前言
今天在瀏覽技術(shù)大牛的公眾號文章秋泳,看到一篇文章講解了如何使用LifeCycle實(shí)現(xiàn)懶加載的新思路潦闲,經(jīng)過學(xué)習(xí)和總結(jié)寫一篇播放博客分享給大家。
原文作者博客:https://juejin.im/post/5e085dafe51d45580769a1eb
(此文章已授權(quán)鴻洋公眾號)
再為大家推薦兩位大牛的公眾號迫皱,對于處于突破拔高期的朋友非常有幫助:
1歉闰、鴻洋大牛也是CSDN的知名博主:https://me.csdn.net/lmj623565791
2、郭霖大牛博客地址:https://me.csdn.net/sinyu890807
正文
對于懶加載的實(shí)現(xiàn)新思路大家可以詳細(xì)閱讀原文卓起,我這里只是一個(gè)學(xué)習(xí)總結(jié)的筆記和敬。首先LifeCycle,主要是給Activity和Fragment對外暴露自己的生命周期的媒介戏阅,這樣一些跟頁面無關(guān)的邏輯就方便單獨(dú)處理昼弟,例如常見的客戶端維護(hù)的Activity堆棧,在之前我們大部分都會寫在BaseActivity的周期中奕筐,現(xiàn)在通過LifeCycle舱痘,我們可以直接放在Application中單獨(dú)處理。
今天我們不討論LifeCycle的用法离赫,只探討LifeCycle對于Fragment的生命周期的影響芭逝。
Fragment問題1:Fragment創(chuàng)建的主要生命周期:
onAttach -> onCreate -> onCreateView -> onStart -> onResume
Fragment問題2:如何改變這個(gè)周期,例如創(chuàng)建的時(shí)候只執(zhí)行到onCreate 或者 onStart笆怠,不會執(zhí)行onResume铝耻?
如果是以前我相信我絕對答不出來。如果想要實(shí)現(xiàn)這個(gè)需求蹬刷,我們可以通過:
FragmentTransaction.setMaxLifecycle(Fragment, Lifecycle.State)
第一個(gè)參數(shù)是要設(shè)置的Fragment瓢捉,不需要解釋;
第二個(gè)參數(shù)是一個(gè)枚舉:
public enum State {
DESTROYED,
INITIALIZED,
CREATED,
STARTED,
RESUMED;
...
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
}
}
其中最常用的是 CREATED,STARTED,RESUMED办成,如果我們設(shè)置了CREATED泡态,你會發(fā)現(xiàn)Fragment創(chuàng)建時(shí)的生命周期變?yōu)椋?/p>
onAttach -> onCreate
如果設(shè)置的是STARTED:
onAttach -> onCreate -> onCreateView -> onStart
為什么setMaxLifecycle可以做到這么神奇的操作,我們從源碼做一個(gè)簡單的分析(源碼的流程實(shí)在是太多了):
1迂卢、把操作保存到列表中
@NonNull
public FragmentTransaction setMaxLifecycle(@NonNull Fragment fragment,
@NonNull Lifecycle.State state) {
// 添加到列表某弦,保存起來
addOp(new Op(OP_SET_MAX_LIFECYCLE, fragment, state));
return this;
}
2桐汤、調(diào)用commit靶壮,把設(shè)置的最大生命周期綁定到Fragment中
FragmentTransaction:
void executeOps() {
...
mManager.setMaxLifecycle(f, op.mCurrentMaxState);
break;
...
}
FragmentManager:
public void setMaxLifecycle(Fragment f, Lifecycle.State state) {
// 請注意,Lifecycle.State.CREATED為最小值腾降,所以不支持 DESTROYED,INITIALIZED,
if (!state.isAtLeast(Lifecycle.State.CREATED)) {
throw new IllegalArgumentException("Cannot set maximum Lifecycle below "
+ Lifecycle.State.CREATED);
}
...
f.mMaxState = state;
}
這里要注意這個(gè)判斷螃壤,Lifecycle.State的最小值是CREATED,所以不支持DESTROYED和INITIALIZED奸晴。
3、在周期分發(fā)的時(shí)候寄啼,根據(jù)MaxLifeState分發(fā)周期:
FragmentActivity:
// 取最小值,保證周期不會超出范圍
if (f.mMaxState == Lifecycle.State.CREATED) {
newState = Math.min(newState, Fragment.CREATED);
} else {
newState = Math.min(newState, f.mMaxState.ordinal());
}
// 判斷是否小于最大周期
if (f.mState <= newState) {
... 分發(fā)周期
}
Fragment問題3:如果是ViewPager辕录,LifeCycle會有哪些影響?
以FragmentStatePagerAdapter為例走诞,我們首先發(fā)現(xiàn)FragmentStatePagerAdapter的構(gòu)造方法最多支持兩個(gè)參數(shù):
public FragmentStatePagerAdapter(@NonNull FragmentManager fm,
@Behavior int behavior) {
mFragmentManager = fm;
mBehavior = behavior;
}
其中behavior默認(rèn)是BEHAVIOR_SET_USER_VISIBLE_HINT:
默認(rèn)值,只為了兼容老版本的setUserVisiableByHint()
還有一個(gè)值是:BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
從命名上看蚣旱,我們可以推測,只有當(dāng)前Fragment才調(diào)用Resume塞绿。
這是一個(gè)單向選擇,如果是BEHAVIOR_SET_USER_VISIBLE_HINT异吻,那么就會和以前一樣,還會回調(diào)setUserVisibleHint诀浪,但是這個(gè)方法已經(jīng)廢棄,我覺得可能有兩種原因:
1雷猪、setUserVisibleHint的周期相對不穩(wěn)定睛竣,所以為了實(shí)現(xiàn)懶加載不得不增加初始化判斷射沟;
2殊者、onResume更符合頁面回到前臺的設(shè)定。
如果設(shè)置的BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT猖吴,當(dāng)前Fragment會回調(diào)onResume,被劃走的Fragment會回調(diào)onPause簿姨,但是不會執(zhí)行setUserVisibleHint。
具體實(shí)現(xiàn)我們看一下源碼:
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
...
if (mBehavior == BEHAVIOR_SET_USER_VISIBLE_HINT) {
fragment.setUserVisibleHint(false);
}
...
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);
}
return fragment;
}
@Override
@SuppressWarnings({"ReferenceEquality", "deprecation"})
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
...
// 不是當(dāng)前Fragment
if (fragment != mCurrentPrimaryItem) {
...
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
...
// 周期只到onCreate
mCurTransaction.setMaxLifecycle(mCurrentPrimaryItem, Lifecycle.State.STARTED);
} else {
mCurrentPrimaryItem.setUserVisibleHint(false);
}
}
else{
...
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
...
// 周期只到onResume
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.RESUMED);
} else {
fragment.setUserVisibleHint(true);
}
}
}
從源碼上看都是if判斷,所以具體選擇選擇方式就要看大家怎么選擇了趁俊。
總結(jié)
以上就是今天的筆記域仇,希望對正在研究LifeCycle的朋友有所幫助暇务,如果有表述不清的地方歡迎留言討論。