LifeCycle在Fragment中的使用

前言

今天在瀏覽技術(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的朋友有所幫助暇务,如果有表述不清的地方歡迎留言討論。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末垦细,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子挡逼,更是在濱河造成了極大的恐慌,老刑警劉巖家坎,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異虱疏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)做瞪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來装蓬,“玉大人,你說我怎么就攤上這事矛物。” “怎么了履羞?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵屡久,是天一觀的道長。 經(jīng)常有香客問我被环,道長,這世上最難降的妖魔是什么筛欢? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮版姑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘迟郎。我一直安慰自己,他們只是感情好宪肖,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著控乾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜕衡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天衷咽,我揣著相機(jī)與錄音,去河邊找鬼镶骗。 笑死桶现,一個(gè)胖子當(dāng)著我的面吹牛鼎姊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播相寇,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼唤衫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起佳励,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤蛆挫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后悴侵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡可免,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浇借。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逮刨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出堵泽,到底是詐尸還是另有隱情恢总,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布片仿,位于F島的核電站,受9級特大地震影響砂豌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜阳距,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望筐摘。 院中可真熱鬧卒茬,春花似錦咖熟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽确沸。三九已至捌锭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間舀锨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工坎匿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人替蔬。 一個(gè)月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像承桥,于是被迫代替她去往敵國和親驻粟。 傳聞我的和親對象是個(gè)殘疾皇子凶异,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容