2021-05-09

Android Fragment懒加载

Android Fragment懒加载已经出来了很多年了,在此对懒加载进行一些总结:

1、使用场景:通常是与ViewPage连用的时候使用。
2、为什么要使用懒加载:当fragment与ViewPage连用的时候,viewpage的预加载机制会使相关联的fragment,会自动加载后一个fragment(当offscreenPageLimit=1的时候),如果 用户不是访问第2个fragment,而是直接访问第三fragment,这样会造成资源的浪费,所以才引出fragment的懒加载机制(即使用当某个fragment时,才加载某个fragment)。
3、实现步骤:在网上看了大多数懒加载,要么讲的不清楚,要么步骤不完成,因此自己也总结了一下,需要使用的技术和步骤:在viewpage中(不是viewpage2)是通过setUserVisibleHint(boolean isVisibleToUser)这个函数来获取当前fragment的显示状态,但是该函数既不是fragment的生命周期函数,也不是fragment中自动调用的函数,而是在viewpager中调用的,并且它是在fragment中所有生命周期之前执行的。我们需要借助该函数来实现懒加载功能:
第一步:我们在BaseFragment中先实现3个方法:数据加载方法,数据停止加载方法和isVisibleToUser的状态分发方法,并且在setUserVisibleHint(boolean isVisibleToUser)方法中调用状态分发方法如下: public void onFragmentLoadStop() {//停止加载
Log.d(TAG,“onFragmentLoadStop”);
}
public void onFragmentLoad() {//数据加载
Log.d(TAG,“onFragmentLoad”);
}

private void dispatchUserVisibleHint(boolean visibleState) {
    if (visibleState) {
        // 加载数据
        onFragmentLoad();
    } else {
        // 停止一切操作
        onFragmentLoadStop();
    }
}
 public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
            dispatchUserVisibleHint(true);
        } else {
            dispatchUserVisibleHint(false);
        }
    }
这样我们便完成第一步的内容,但是我们使用这些代码时,却发现崩溃,原因是,当我在停止加载方法中更新了UI,导致控件未进行初始化,爆出了可恶的空指针异常,所以我继续下一步的改造,即判断view是否被初始化,如果初始化后,我们执行以上的代码:
 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    if (rootView == null) {
        rootView = inflater.inflate(getLayoutRes(),container, false);
    }
    isViewCreated  = true;//记录是否初始化
    initView(rootView);
    return rootView;
}

 public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if(isViewCreated  ){
        if (isVisibleToUser) {
            dispatchUserVisibleHint(true);
        } else {
            dispatchUserVisibleHint(false);
        }
    }}
    完成代码后,我们又发现了新问题,第一次加载数据的时候,fragment既然为空白,还是因为第一次的isViewCreated  的值是false,在setUserVisibleHint中,没有相应的操作,所以就没有数据,但是我们可以在oncreateView中进行一次重新分发
    if (getUserVisibleHint()) {//表示已经可见的状态
        setUserVisibleHint(true);//手动分发一次
   }
   如果你认为现在是完成了一个懒加载的流程,那你就错了,因为这样的话,会导致整个数据错误乱,所以我们还得修改,因为fragment的状态是由可见到不可见或是由不可见到可见状态,那我们可以从这个方面下手:即记录上一次的状态,如果是由不可见到可见状态,那我们就可以分发true,否则为false
   private boolean isVisibleStateUP = false;// 记录上一次的可见状态
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isViewCreated) {
        if (isVisibleToUser && !isVisibleStateUP) {//由不可见到可见,分发为ture
            dispatchUserVisibleHint(true);
        } else if (!isVisibleToUser && isVisibleStateUP){//否则为false
            dispatchUserVisibleHint(false);
        }
    }
}
    private void dispatchUserVisibleHint(boolean visibleState) {
    this.isVisibleStateUP = visibleState //更新状态
    if (visibleState) {
        onFragmentLoad();
    } else {
        onFragmentLoadStop();
    }
}
这样的话,这个fragment懒加载才算一个小结,但是对于我们程序员来说,这个还不是最好的结果,比如,这些fragment可以通过某个动作,跳转到其他Activity,或者暂时退出了,马上又回来这种情况,我们应该怎么处理呐,我们可以在fragment的onResume与onPause中处理,因为fragment的状态对于我们来说还是由可见到不可见,或者不可见到可见
public void onResume() {
    super.onResume();
    if (getUserVisibleHint() && !isVisibleStateUP) {//不可见到可见,重新分发
        dispatchUserVisibleHint(true);
    }
}

public void onPause() {
    super.onPause();
    if (!getUserVisibleHint() && isVisibleStateUP) {//由可见到不可见
        dispatchUserVisibleHint(false);
    }
}

以上为懒加载的基本流程,但是这个流程并不完整,因为fragment中可能会存在很多情况,比如嵌套viewpager等,这里就不一一写出来了,如果有描述得不好的地方,请见谅

上一篇:databinding原理,34岁安卓开发大叔感慨,满满干货指导


下一篇:[CTF]picoCTF-day1