Fragment懒加载

Fragment+ViewPager

Fragment 与 ViewPager结合使用时由于ViewPager会预加载左右两侧相邻的1个Fragment,Activity启动后主页Fragment包括其他Fragment生命周期也会开始,导致多处同时加载数据

1
2
3
4
5
6
7
8
9
10
11
public void setOffscreenPageLimit(int limit) {
//DEFAULT_OFFSCREEN_PAGES为1
if (limit < DEFAULT_OFFSCREEN_PAGES) {
limit = DEFAULT_OFFSCREEN_PAGES;
}
if (limit != mOffscreenPageLimit) {
mOffscreenPageLimit = limit;
populate();
}
}
//Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state.

重写ViewPager法

复制所有ViewPager代码,在setOffscreenPageLimit中将if (limit < DEFAULT_OFFSCREEN_PAGES) { limit = DEFAULT_OFFSCREEN_PAGES; }删除就能实现点击之后再加载,但是会造成不能fragment状态,每次点击之后都会重新执行生命周期

普通懒加载

懒加载需要重写Fragment中的setUserVisibleHint(Set a hint to the system about whether this fragment's UI is currently visible)

1
2
3
4
5
6
7
8
9
10
11
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
//isVisibleToUser这个boolean值表示:该Fragment的UI 用户是否可见
if (isVisibleToUser) {
isUIVisible = true;
lazyLoad();
} else {
isUIVisible = false;
}
}

lazyLoad中会进行一些数据更新、视图更新,但setUserVisibleHint为true时,生命周期可能未执行,获取的activity为null,导致空指针异常,见下前提1

加强版懒加载法

前提

  1. setUserVisibleHint和生命周期无关,getUserVisibleHint为true时生命周期也很可能未开始(因为仅仅是一种意图,标记此fragment可见)

  2. ViewPager创建好,currentItem的fragment以及左右OffscreenPageLimit范围内fragment均开始执行生命周期直到onResumed()

  3. 只要切换到新fragment后,新fragment的setUserVisibleHint一定执行

解决首页

1.首页存在的问题:setUserVisibleHint中为true时,生命周期还未开始

2.解决方法:对于可见且未加载过,我们标记为canLoad,在生命周期开始后,如果canLoad为true且未加载过,就去执行lazyLoad()

1
2
3
4
5
6
7
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (getUserVisibleHint()&&!isLoaded) {
canLoad = true;
}
}
1
2
3
4
5
6
7
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = inflater.inflate(getLayoutId(), container, false);
if (canLoad&&!isLoaded){
lazyLoad();
}
return view;
}

After 首页

1.After 首页存在的问题:所有fragment均已执行生命周期到onResume(),在非首页中执行 onCreateView ()时,canLoad为false,不执行lazyLoad(),符合我们要的效果,但是点击非首页之后setUserVisibleHint中将canLoad置为true,但不执行lazyLoad()(生命周期已执行到onResume()),不符合我们的的需求

2.解决方法:setUserVisibleHint中判断可见&&未加载&&生命周期执行 就去lazyLoad()

1
2
3
4
5
6
7
8
9
10
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (getUserVisibleHint()&&!isLoaded) {
canLoad = true;
}
if (getUserVisibleHint() && !isLoaded && isPrepared){
lazyLoad();
}
}
1
2
3
4
5
6
7
8
9
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = inflater.inflate(getLayoutId(), container, false);
if (canLoad&&!isLoaded){
lazyLoad();
}
isPrepared = true;
return view;
}

成功加载后执行isLoaded = true; 不可见到可见时将不再执行lazyLoad()