背景:项目中每个页面多个地方使用到Fragment,有的是在viewpager中,有的自己进行管理;项目运行一段时间后想对fragment进行懒加载处理,很早之前只对ViewPager中的Fragment进行过处理,结果在处理过程中遇到的一些问题。
先看一段代码
public abstract class BaseFragment extends Fragment {
private boolean isFirstVisible = true;
private boolean isFirstInvisible = true;
private boolean isViewCreated;
private boolean isUIVisible;
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
isViewCreated = true;
lazyLoad(); // 执行懒加载,因为无法确定setUserVisibleHint和onViewCreated哪个方法先执行,因此两个方法里面都需要调用lazyLoad
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
isUIVisible = true; //当前fragment可见
if (isFirstVisible) {
//如果是第一次可见,则进行懒加载
isFirstVisible = false;
lazyLoad();
} else {
//不是第一次可见,则调用onUserVisible()
onUserVisible();
}
} else {
isUIVisible = false;
if (isFirstInvisible) {
isFirstInvisible = false;
//第一次不可见
onFirstUserInvisible();
} else {
//非第一次不可见
onUserInvisible();
}
}
}
private void lazyLoad() {
if (isViewCreated && isUIVisible) { //需要进行双重判断,避免因为setUserVisibleHint先于onViewCreaetd调用时,出现空指针
LogUtils.e( this.getClass().getSimpleName() + "lazyLoad");
// initViewsAndEvents();
onFirstUserVisible(); //进行初次可见时的加载
}else {
LogUtils.e( this.getClass().getSimpleName() + ">>>>isViewCreated:" + isViewCreated + "------>>>>>isUIVisible:" + isUIVisible);
}
}
protected abstract void onFirstUserVisible();
protected abstract void onUserVisible();
protected abstract void onFirstUserInvisible();
protected abstract void onUserInvisible();
}
一般ViewPager+Fragment的时候,主要使用到了setUserVisibleHint()方法进行判断Fragment是否可见,来进行懒加载处理。
但是
但是
但是
在某些场景中setUserVisibleHint()竟然没有执行~~~~:在未使用Viewpager,而是自己通过FragmentTransaction 对Fragment进行add hide show操作,setUserVisibleHint()方法没有被调用。原因是hide()和show()方法调用时,Fragment不走任何的生命周期。
这时候突然发现另外一个Fragment方法onhiddenchanged(),该方法用于判断fragment显隐,正好切合hide show操作。
public abstract class LazyFragment extends BaseFragment {
public static final String TAG = LazyFragment.class.getSimpleName();
private boolean hasLoaded = false;
private boolean isCreated = false;
private boolean isVisibleToUser = false;
private View view;
@Override
protected void initViews(View view, @Nullable Bundle savedInstanceState) {
isCreated = true;
this.view = view;
lazyLoad(this.view, savedInstanceState);
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
this.isVisibleToUser = isVisibleToUser;//注:关键步骤
super.setUserVisibleHint(isVisibleToUser);
lazyLoad(view, null);
}
private void lazyLoad(View view, Bundle savedInstanceState) {
if (!isVisibleToUser || hasLoaded || !isCreated) {
return;
}
lazyInitView(view, savedInstanceState);
hasLoaded = true;//注:关键步骤,确保数据只加载一次
}
public abstract void lazyInitView(View view, Bundle savedInstanceState);
@Override
public void onDestroyView() {
super.onDestroyView();
isCreated = false;
hasLoaded = false;
}
}
然后对BaseFragment进行进一步封装,应对各种情况。
总结
onhiddenchanged()
用FragmentTransaction来控制fragment的hide和show时,那么这个方法就会被调用。每当你对某个Fragment使用hide或者是show的时候,那么这个Fragment就会自动调用这个方法。
(使用情况:你自己去管理Fragment,而不是用viewpager管理的时候)
setUserVisibleHin()
在使用viewpager的时候,viewpager内部有个提前缓存的机制(默认是提前缓存一页),比如你在看第一个Fragment的时候,隔壁的Fragment已经创建好了,但此时的状态却是不可见的。
但是这时候Fragment不会去调用上面说的onhiddenchanged方法,只会调用setUserVisibleHint这个方法。
参考