安卓性能优化之懒加载的原理及实现(超详细仿微信头条实现Fragment数据懒加载)

在讲代码之前理解三个概念,以便理解懒加载的实现过程,当前Fragment、目标Fragment和缓存Fragment。
例如:页面有三个Fragment:Fragment1、Fragment2 、Fragment3,当用户在Fragment1上进行操作,打算跳到Fragment2中,则三个角色分别为

  1. 当前Fragment:当前用户操作的fragment,即Fragment1。
  2. 目标Fragment:要切换的fragment,即Fragment2。
  3. 缓存Fragment:预加载的Fragment,即Fragment3。

首先看定义的三个成员变量:

boolean mIsViewCreated=false;//Fragment是否已经创建,
boolean mIsFirstVisiable=true;//Fragment是否第一次可见
boolean mCurrentVisiableState=false;//标记保存Fragment的可见状态,表示当前Fragment是否分发过, 可见到不可见 不可见到可见才可以调用 disPatchVisibaleHint 防止重复调用

step1:setUserVisibleHint方法的逻辑处理

因为setUserVisibleHint方法是最先执行的在此先看他的实现

//与生命周期无关的函数
/**

  • onCreateView在此方法之后 第一次时 mIsViewCreated=false
  • @param isVisibleToUser
    /
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
    //用户是否可见
    Log.e(TAG,“setUserVisibleHint----”+isVisibleToUser);
    super.setUserVisibleHint(isVisibleToUser);
    /
    *
  • 1:分发的前提是FragmentView已经创建,因为setUserVisibleHint在fragment 的声明周期之前执行,
  • 如果页面没创建就去分发容易造成空指针异常
  • 2:因为此方法是由setUserVisibleHint方法调用,而setUserVisibleHint方法由系统的Viewpager调用多次,我们没办法控制它,
  • 但是我们可以控制disPatchVisibaleHint的分发
    */
    if (mIsViewCreated){
    //只有Fragment创建了后才进行分发
    if (isVisibleToUser&& !mCurrentVisiableState){//防止重复调用disPatchVisibaleHint !mCurrentVisiableState表示没有分发过时才分发
    //用户可见时进行分发事件
    disPatchVisibaleHint(true);
    }else if (mCurrentVisiableState&& !isVisibleToUser){
    //用户不可见时不分发事件
    disPatchVisibaleHint(false);
    }
    }
    }

/**

  • 分发可见
  • 调用的前提:可见–》不可见 或者不可见–》可见
  • @param isVisiable
    */
    private void disPatchVisibaleHint(boolean isVisiable) {
    Log.e(TAG,“disPatchVisibaleHint----”+isVisiable);

if (mCurrentVisiableState==isVisiable){
//防止调用两次更新,存在当 mCurrentVisiableState=isVisiable;执行前setUserVisibleHint可能被调用两次
return;
}
mCurrentVisiableState=isVisiable;//进行赋值操作
if (isVisiable){
//可见
if (mIsFirstVisiable){
mIsFirstVisiable=false;
//处理第一次可见时
//公共方法,由子类实现
onFragmentFirstVisiable();
}
//复写onFragmentResume分发事件,网路请求
onFragmentResume();
//对viewpager嵌套使用时处理子的fragment
dispatChChildVisiableState(true);
}else {
//复写onFragmentPause终止数据请求
onFragmentPause();
//对viewpager嵌套使用时处理子的fragment
dispatChChildVisiableState(false);
}
}
/**

  • 下面抽取三个方法定义成public方法是因为:
  • 父类不知道子类要不要处理可见和不可见,因为子类有可能不需要懒加载,此时子类什么也不需要做
  • 当需要懒加载时,才需要复写这三个方法。
  • 因此这3个方法是非必须实现的方法,不能定义成抽象方法
    */

/**

  • 第一次可见时特殊处理
    */
    public void onFragmentFirstVisiable() {
    Log.e(TAG,“onFragmentFirstVisiable”);
    }

/**

  • 不可见时处理相关动作 停止数据的加载
    */
    public void onFragmentPause() {
    Log.e(TAG,“onFragmentPause”);
    }

/**

  • 表面可见时 加载数据
    */
    public void onFragmentResume() {
    Log.e(TAG,“onFragmentResume”);
    }
step2:onCreateView函数的实现

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
TAG=getClass().getSimpleName()+“----”;
Log.e(TAG,“onCreateView”);
//两个抽象方法,让子类实现initView和getLayoutRes
if (mRootView==null) {
mRootView=inflater.inflate(getLayoutRes(),null);
}
initView(mRootView);
//1:创建了Fragment 控制下面分发的前提,因为分发事件由setUserVisibleHint方法控制,而setUserVisibleHint最先执行
mIsViewCreated=true;

//2:对于默认Fragment的加载,可以在此分发一下,可见才分发
if (getUserVisibleHint()&&!isHidden()){
//可见
disPatchVisibaleHint(true);
}
return mRootView;
}

step3: onPause方法的实现

这里需要描述一下场景,当从fragment跳转到另一个Activity时需要做的处理,
只需对当前用户可见的Fragment的数据加载进行终止

@Override
public void onPause() {
Log.e(TAG,“onPause”);
if (mCurrentVisiableState&&getUserVisibleHint()){
disPatchVisibaleHint(false );
}
super.onPause();
}

step4: onResume方法的实现

这里需要描述一下场景,经过Step3后,又再次返回到Frangment所在的Activity时,只需要对当前用户可见的Fragment的数据加载

@Override
public void onResume() {
Log.e(TAG,“onResume”);
//只有当前可见的Fragment 才更新shuju 点击home键又返回
if (!mCurrentVisiableState&&getUserVisibleHint()&&!isHidden() ){
disPatchVisibaleHint(true );
}
super.onResume();
}

step5: onDestroyView方法的实现

主要是对控制变量进行恢复初始值操作##

@Override
public void onDestroyView() {
Log.e(TAG,“onDestroyView”);
super.onDestroyView();
//将所有的变量复位
mIsFirstVisiable=true;
mCurrentVisiableState=false;
mIsViewCreated=false;
}

step6:onHiddenChanged方法的实现

@Override
//与生命周期无关的函数
//在使用FragmentTransactionhiddenshow方法管理fragment时,是不会走Fragment正常的生命周期,
// 而是走onHiddenChanged方法,此方法可以监听Fragment 的显示与隐藏。
public void onHiddenChanged(boolean hidden) {
Log.e(TAG,“onHiddenChanged”);
// FragmentTransaction管理Fragment时
super.onHiddenChanged(hidden);
if (hidden){
disPatchVisibaleHint(false);
}else {
disPatchVisibaleHint(true);
}
}

到此与懒加载相关的六个方法的逻辑已经处理完毕,详细原理请看代码中的注解,再此不做过多赘述,在step1中的disPatchVisibaleHint方法中处理ViewPager嵌套使用时,对于子ViewPager中的Frangment处理交给了dispatChChildVisiableState方法,那这个处理过程是怎么什么样子的呢?请接着往下看。

4:懒加载之进阶ViewPager+Fragment的嵌套使用时子ViewPager的Frangment如何实现懒加载

先说原理:很简单,就是根据当父的Fragment对用户的可见状态,去处理子ViewPager中Fragment的事件分发。就是在上面disPatchVisibaleHint方法中
在这里插入图片描述

代码实现:

/**

  • ViewPage嵌套使用时处理子的Fragment懒加载逻辑
  • 通过getChildFragmentManager();获取子Fragment
  • @param visiable
    */
    private void dispatChChildVisiableState(boolean visiable){
    Log.e(TAG,"dispatChChildVisiableState ===== " + visiable);
    FragmentManager childFragmentManager = getChildFragmentManager();
    List childFragmentManagerFragments = childFragmentManager.getFragments();
    if (childFragmentManagerFragments != null) {
    for (Fragment fragment : childFragmentManagerFragments) {
    //进行类型校验,只有继承了LazyFragment才进行懒加载的处理
    if (fragment instanceof LazyFragment&&!fragment.isHidden()&&fragment.getUserVisibleHint()){
    ((LazyFragment) fragment).disPatchVisibaleHint(visiable);
    }
    }
    }
    }

5:最后附上封装好的LazyFragment的完整代码和下载地址:

public abstract class LazyFragment extends Fragment {
public String TAG=“—”;

View mRootView;
boolean mIsViewCreated=false;//Fragment是否已经创建,
boolean mIsFirstVisiable=true;//Fragment是否第一次可见
boolean mCurrentVisiableState=false;//标记保存Fragment的可见状态,表示当前Fragment是否分发过 可见到不可见 不可见到可见才可以调用 disPatchVisibaleHint 防止重复调用

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
TAG=getClass().getSimpleName()+“----”;
Log.e(TAG,“onCreateView”);
//两个抽象方法,让子类实现initView和getLayoutRes
if (mRootView==null) {
mRootView=inflater.inflate(getLayoutRes(),null);
}
initView(mRootView);
//1:创建了Fragment 控制下面分发的前提,因为分发事件由setUserVisibleHint方法控制,而setUserVisibleHint最先执行
mIsViewCreated=true;

//2:对于默认Fragment的加载,可以在此分发一下,可见才分发
if (getUserVisibleHint()&&!isHidden()){
//可见
disPatchVisibaleHint(true);
}
return mRootView;
}

@Override
public void onResume() {
Log.e(TAG,“onResume”);
//只有当前可见的Fragment 才更新shuju 点击home键又返回
if (!mCurrentVisiableState&&getUserVisibleHint()&&!isHidden() ){
disPatchVisibaleHint(true );
}
super.onResume();
}

@Override
public void onPause() {
Log.e(TAG,“onPause”);
if (mCurrentVisiableState&&getUserVisibleHint()){
disPatchVisibaleHint(false );
}
super.onPause();
}

@Override
public void onDestroyView() {
Log.e(TAG,“onDestroyView”);
super.onDestroyView();
//将所有的变量复位
mIsFirstVisiable=true;
mCurrentVisiableState=false;
mIsViewCreated=false;
}

//与生命周期无关的函数
/**

  • onCreateView在此方法之后 第一次时 mIsViewCreated=false
  • @param isVisibleToUser
    /
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
    //用户是否可见
    Log.e(TAG,“setUserVisibleHint----”+isVisibleToUser);
    super.setUserVisibleHint(isVisibleToUser);
    /
    *
  • 1:分发的前提是FragmentView已经创建,因为setUserVisibleHint在fragment 的声明周期之前执行,
  • 如果页面没创建就去分发容易造成空指针异常
  • 2:因为此方法是由setUserVisibleHint方法调用,而setUserVisibleHint方法由系统的Viewpager调用多次,我们没办法控制它,
  • 但是我们可以控制disPatchVisibaleHint的分发
    */
    if (mIsViewCreated){
    //只有Fragment创建了后才进行分发
    if (isVisibleToUser&& !mCurrentVisiableState){//防止重复调用disPatchVisibaleHint !mCurrentVisiableState表示没有分发过时才分发
    //用户可见时进行分发事件
    disPatchVisibaleHint(true);
    }else if (mCurrentVisiableState&& !isVisibleToUser){
    //用户不可见时不分发事件
    disPatchVisibaleHint(false);
    }
    }
    }

@Override
//与生命周期无关的函数
//在使用FragmentTransactionhiddenshow方法管理fragment时,是不会走Fragment正常的生命周期,
// 而是走onHiddenChanged方法,此方法可以监听Fragment 的显示与隐藏。
public void onHiddenChanged(boolean hidden) {
Log.e(TAG,“onHiddenChanged”);
// FragmentTransaction管理Fragment时
super.onHiddenChanged(hidden);
if (hidden){
disPatchVisibaleHint(false);
}else {
disPatchVisibaleHint(true);
}

}

/**

  • 分发可见
  • 调用的前提:可见–》不可见 或者不可见–》可见
  • @param isVisiable
    */
    private void disPatchVisibaleHint(boolean isVisiable) {
    Log.e(TAG,“disPatchVisibaleHint----”+isVisiable);

if (mCurrentVisiableState==isVisiable){
//防止调用两次更新,存在当 mCurrentVisiableState=isVisiable;执行前setUserVisibleHint可能被调用两次
return;
}
mCurrentVisiableState=isVisiable;//进行赋值操作
if (isVisiable){
//可见
if (mIsFirstVisiable){
mIsFirstVisiable=false;
onFragmentFirstVisiable();
}
onFragmentResume();
//处理子ViewPager嵌套使用时,子fragment懒加载的实现
dispatChChildVisiableState(true);
}else {
onFragmentPause();
dispatChChildVisiableState(false);
}

}

/**

  • 下面抽取三个方法定义成public方法是因为:
  • 父类不知道子类要不要处理可见和不可见,因为子类有可能不需要懒加载,此时子类什么也不需要做
  • 当需要懒加载时,才需要复写这三个方法。
  • 因此这3个方法是非必须实现的方法,不能定义成抽象方法
    */

/**

  • 第一次可见时特殊处理
    */
    public void onFragmentFirstVisiable() {
    Log.e(TAG,“onFragmentFirstVisiable”);

}

/**

  • 不可见时处理相关动作 停止数据的加载
    */
    public void onFragmentPause() {
    Log.e(TAG,“onFragmentPause”);

}

/**

  • 表面可见时 加载数据
    */
    public void onFragmentResume() {
    Log.e(TAG,“onFragmentResume”);

}

/**

  • ViewPage嵌套使用时处理子的Fragment懒加载逻辑
  • 通过getChildFragmentManager();获取子Fragment
  • @param visiable
    */
    private void dispatChChildVisiableState(boolean visiable){

最后

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

上面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

【Android高级架构视频学习资源】

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

需要这份系统化学习资料的朋友,可以戳这里获取

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

),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

[外链图片转存中…(img-5ayWw3y0-1714624494938)]

【Android高级架构视频学习资源】

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

需要这份系统化学习资料的朋友,可以戳这里获取

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

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值