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等,这里就不一一写出来了,如果有描述得不好的地方,请见谅