Android面试题避坑:ViewPager中的Framgent如何实现懒加载?_behavior_resume_only_current_fragment

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

    fragmentList.add(Fragment2())
    fragmentList.add(Fragment3())
    // 为MyPagerAdapter适配器设置FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT 参数
    val myPagerAdapter: MyPagerAdapter = MyPagerAdapter(
        getSupportFragmentManager(),
        FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT, fragmentList
    )
    viewPager.setAdapter(myPagerAdapter)
    // 设置预加载为3页,来测试懒加载是否成功
    viewPager.offscreenPageLimit = 3
}

class MyPagerAdapter(
    fm: FragmentManager,
    behavior: Int,
    val fragmentList: List<Fragment>
) :
    FragmentPagerAdapter(fm, behavior) {

    override fun getCount() = fragmentList.size
    override fun getItem(position: Int) = fragmentList[position]

}

}


FragmentPagerAdapter 在创建 Fragment后,根据 behavior 调用了setMaxLifecycle。



//FragmentPagerAdapter.java

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

@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {

if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
// mBehaviour为1的时候走新逻辑
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
// 初始化item时将其生命周期限制为STARTED
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);
} else {
// 兼容旧版逻辑
fragment.setUserVisibleHint(false);
}
}

return fragment;

}

@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
Fragment fragment = (Fragment)object;
if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {

// 滑走的会变成非主item, 设置其Lifecycle为STARTED
mCurTransaction.setMaxLifecycle(mCurrentPrimaryItem, Lifecycle.State.STARTED);
} else {
mCurrentPrimaryItem.setUserVisibleHint(false);
}
}
fragment.setMenuVisibility(true);
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {

// 设置新滑到的主item的Lifecycle为RESUMED
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.RESUMED);
} else {
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}


不借助 behavior,在自定义Adapter中构建 Framgent时直接调用setMaxLifecycle 也是等价的。


#### setMaxLifecycle 实现原理


setMaxLifecycle 使用方法很简单,接下来通过梳理源码了解一下实现原理(基于1.3.0-rc01),即使面试官追问其原理你也能沉着应对。


**OP\_SET\_MAX\_LIFECYCLE**


我们知道 FramgentTransition 对 Fragment 的所有操作都将转换为一个Op,针对setMaxLifecycle也同样增加了一个新的Op -- `OP_SET_MAX_LIFECYCLE`, 专门用来设置生命周期的上限。



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


当 FramgentTransition 对 Frament 添加了 OP\_SET\_MAX\_LIFECYCLE 后,在实现类 BackStackRecord 中, FragmentManager 会遍历 Transaction 的 Op 列表



void executeOps() {
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
final Fragment f = op.mFragment;
//…
switch (op.mCmd) {
//…
// 新引入的这个Op类型, 在这里会给这个Fragment设置允许的生命周期上限
case OP_SET_MAX_LIFECYCLE:
mManager.setMaxLifecycle(f, op.mCurrentMaxState);
break;
//…
}
}


当遇到 OP\_SET\_MAX\_LIFECYCLE 时,通过调用 FragmentManager 的 setMaxLifeCycle 方法设置 fragment 的 mMaxState,以标记其生命周期上限



void setMaxLifecycle(@NonNull Fragment f, @NonNull Lifecycle.State state) {
//…
f.mMaxState = state;
}


**FragmentStateManager**


FragmentManager 通过 FragmentStateManager 推进 Fragment 的生命周期。 推进过程中根据 mMaxState 对生命周期


值得一提的是,FragmentStateManager 是 1.3.0-alpha08 之后新增的类,将原来和 State 相关的逻辑从FragmentManager 抽离了出来, 降低了与 Fragment 的耦合, 职责更加单一。


![](https://img-blog.csdnimg.cn/img_convert/dc29ff1568df243549116a4d5dd68383.png)


看一下在 FragmentStateManager 中具体是如何推进 Fragment 生命周期的:



void moveToExpectedState() {
try {

// 循环计算声明周期是否可以推进
while ((newState = computeExpectedState()) != mFragment.mState) {
if (newState > mFragment.mState) {
// 生命周期向前推进
int nextStep = mFragment.mState + 1;
//…
switch (nextStep) {
//…
case Fragment.ACTIVITY_CREATED:
//…
case Fragment.STARTED:
start();
break;
//…
case Fragment.RESUMED:
resume();
break;
}
} else {
// 如果应有的生命周期小于当前, 后退
int nextStep = mFragment.mState - 1;
//…
switch (nextStep) {
// 与上面的switch类似
//…
}
}
}

}

}



int computeExpectedState() {
// 其他计算expected state的逻辑, 算出maxState
//…

// mMaxState 对生命周期做出限制
switch (mFragment.mMaxState) {
    case RESUMED:
        break;
    case STARTED:
        maxState = Math.min(maxState, Fragment.STARTED);
        break;
    case CREATED:
        maxState = Math.min(maxState, Fragment.CREATED);
        break;
    default:
        maxState = Math.min(maxState, Fragment.INITIALIZING);
}

// 其他计算expected state的逻辑, 算出 maxState
// ...
return maxState;

}


整体流程图如下


![](https://img-blog.csdnimg.cn/img_convert/71921e979185987a6634b90b0cb76ebd.png)


#### 最后


除了使用默认的 BEHAVIOR\_RESUME\_ONLY\_CURRENT\_FRAGMENT,我们甚至可以在自定义 Adapter 的instantiateItem 中为将 Fragment的 MaxLifecycle 设置为 `CREATED`, 这样可以让 Fragment 只走到onCreate 从而延迟更多操作,比如在 onCreateView 中的 inflate 以及 onViewCreated 中的一些操作。 Fragment 1.3.0-rc01 已经支持设置最大生命周期为 `INITIALIZED`


面试前复习路线参考



### 总结

其实客户端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

![Android大厂面试真题全套解析](https://img-blog.csdnimg.cn/img_convert/7d6bd239d519425205dc510fe67c6847.webp?x-oss-process=image/format,png)

![2017-2020字节跳动Android面试真题解析PDF](https://img-blog.csdnimg.cn/img_convert/cdeaa31aa5e4e3e963b048d5ebdd54fb.webp?x-oss-process=image/format,png)
然而Android架构学习进阶是一条漫长而艰苦的道路,不能靠一时激情,更不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:**贵在坚持!**



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)**
![img](https://img-blog.csdnimg.cn/img_convert/e0275a1ba4cba8972107c87a371cbf8a.png)

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

的习惯。所以:**贵在坚持!**



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)**
[外链图片转存中...(img-U9CgY5UR-1713049014192)]

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值