LifeCycle在Fragment中的使用

前言

今天在浏览技术大牛的公众号文章,看到一篇文章讲解了如何使用LifeCycle实现懒加载的新思路,经过学习和总结写一篇播放博客分享给大家。

原文作者博客:https://juejin.im/post/5e085dafe51d45580769a1eb
(此文章已授权鸿洋公众号)

再为大家推荐两位大牛的公众号,对于处于突破拔高期的朋友非常有帮助:
1、鸿洋大牛也是CSDN的知名博主:https://me.csdn.net/lmj623565791

鸿洋公众号

2、郭霖大牛博客地址:https://me.csdn.net/sinyu890807
郭霖公众号

正文

对于懒加载的实现新思路大家可以详细阅读原文,我这里只是一个学习总结的笔记。首先LifeCycle,主要是给Activity和Fragment对外暴露自己的生命周期的媒介,这样一些跟页面无关的逻辑就方便单独处理,例如常见的客户端维护的Activity堆栈,在之前我们大部分都会写在BaseActivity的周期中,现在通过LifeCycle,我们可以直接放在Application中单独处理。

今天我们不讨论LifeCycle的用法,只探讨LifeCycle对于Fragment的生命周期的影响。

Fragment问题1:Fragment创建的主要生命周期:

onAttach -> onCreate -> onCreateView -> onStart -> onResume

Fragment问题2:如何改变这个周期,例如创建的时候只执行到onCreate 或者 onStart,不会执行onResume?

如果是以前我相信我绝对答不出来。如果想要实现这个需求,我们可以通过:

FragmentTransaction.setMaxLifecycle(Fragment,  Lifecycle.State)

第一个参数是要设置的Fragment,不需要解释;
第二个参数是一个枚举:

  public enum State {
        DESTROYED,
        INITIALIZED,
        CREATED,
        STARTED,
        RESUMED;
        ...
        public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }
    }
}

其中最常用的是 CREATED,STARTED,RESUMED,如果我们设置了CREATED,你会发现Fragment创建时的生命周期变为:

onAttach -> onCreate

如果设置的是STARTED:

onAttach -> onCreate -> onCreateView -> onStart

为什么setMaxLifecycle可以做到这么神奇的操作,我们从源码做一个简单的分析(源码的流程实在是太多了):

1、把操作保存到列表中

@NonNull
public FragmentTransaction setMaxLifecycle(@NonNull Fragment fragment,
            @NonNull Lifecycle.State state) {
   // 添加到列表,保存起来
   addOp(new Op(OP_SET_MAX_LIFECYCLE, fragment, state));
   return this;
}

2、调用commit,把设置的最大生命周期绑定到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;
}

这里要注意这个判断,Lifecycle.State的最小值是CREATED,所以不支持DESTROYED和INITIALIZED。

3、在周期分发的时候,根据MaxLifeState分发周期:

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) {
    ... 分发周期
}

Fragment问题3:如果是ViewPager,LifeCycle会有哪些影响?

以FragmentStatePagerAdapter为例,我们首先发现FragmentStatePagerAdapter的构造方法最多支持两个参数:

 public FragmentStatePagerAdapter(@NonNull FragmentManager fm,
            @Behavior int behavior) {
      mFragmentManager = fm;
      mBehavior = behavior;
}

其中behavior默认是BEHAVIOR_SET_USER_VISIBLE_HINT:

默认值,只为了兼容老版本的setUserVisiableByHint()

还有一个值是:BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT

从命名上看,我们可以推测,只有当前Fragment才调用Resume。

这是一个单向选择,如果是BEHAVIOR_SET_USER_VISIBLE_HINT,那么就会和以前一样,还会回调setUserVisibleHint,但是这个方法已经废弃,我觉得可能有两种原因:

1、setUserVisibleHint的周期相对不稳定,所以为了实现懒加载不得不增加初始化判断;
2、onResume更符合页面回到前台的设定。

如果设置的BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT,当前Fragment会回调onResume,被划走的Fragment会回调onPause,但是不会执行setUserVisibleHint。

具体实现我们看一下源码:

@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) {
      ...
      // 不是当前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判断,所以具体选择选择方式就要看大家怎么选择了。

总结

以上就是今天的笔记,希望对正在研究LifeCycle的朋友有所帮助,如果有表述不清的地方欢迎留言讨论。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容