【Android TimeCat】 懒加载需求下的BaseFragment封装

背景

在多个Fragment需要加载的时候,启动速度往往会变慢,影响用户体验。分析发现并非所有的Fragment都需要第一时间将数据填充完毕,因为它们都还没有被用户所”看见”.所以我们要达到的效果是Fragment被显示后才加载数据(lazy load)。由于这种需求具有共性,即每个Fragment都可能有懒加载的需要,故封装成基类BaseFragment.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
public abstract class BaseFragment extends Fragment {
/**
* Fragment title
*/
public String fragmentTitle;
/**
* 是否可见状态 为了避免和{@link Fragment#isVisible()}冲突 换个名字
*/
private boolean isFragmentVisible;
/**
* 标志位,View已经初始化完成。
*/
private boolean isPrepared;
/**
* 是否第一次加载
*/
private boolean isFirstLoad = true;
/**
* <pre>
* 忽略isFirstLoad的值,强制刷新数据,但仍要Visible & Prepared
* 一般用于PagerAdapter需要刷新各个子Fragment的场景
* 不要new 新的 PagerAdapter 而采取reset数据的方式
* 所以要求Fragment重新走initData方法
* 故使用 {@link BaseFragment#setForceLoad(boolean)}来让Fragment下次执行initData
* </pre>
*/
private boolean forceLoad = false;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
if (bundle != null && bundle.size() > 0) {
initVariables(bundle);
}
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// 若 viewpager 不设置 setOffscreenPageLimit 或设置数量不够
// 销毁的Fragment onCreateView 每次都会执行(但实体类没有从内存销毁)
isFirstLoad = true;
View view = initViews(inflater, container, savedInstanceState);
isPrepared = true;
lazyLoad();
return view;
}

/**
* 如果是与ViewPager一起使用,调用的是setUserVisibleHint
*
* @param isVisibleToUser 是否显示出来了
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (getUserVisibleHint()) {
onVisible();
} else {
onInvisible();
}
}

/**
* 如果是通过FragmentTransaction的show和hide的方法来控制显示,调用的是onHiddenChanged.
* 若是初始就show的Fragment 为了触发该事件 需要先hide再show
*
* @param hidden hidden True if the fragment is now hidden, false if it is not
* visible.
*/
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (!hidden) {
onVisible();
} else {
onInvisible();
}
}

protected void onVisible() {
isFragmentVisible = true;
lazyLoad();
}

protected void onInvisible() {
isFragmentVisible = false;
}

/**
* 要实现延迟加载Fragment内容,需要在 onCreateView
* isPrepared = true;
*/
protected void lazyLoad() {
if (isPrepared() && isFragmentVisible()) {
if (forceLoad || isFirstLoad()) {
forceLoad = false;
isFirstLoad = false;
initData();
}
}
}

@Override
public void onDestroyView() {
super.onDestroyView();
isPrepared = false;
}

/**
* 被ViewPager移出的Fragment 下次显示时会从getArguments()中重新获取数据
* 所以若需要刷新被移除Fragment内的数据需要重新put数据 eg:
* Bundle args = getArguments();
* if (args != null) {
* args.putParcelable(KEY, info);
* }
*/
public void initVariables(Bundle bundle) {}

protected abstract View initViews(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);

protected abstract void initData();

public boolean isPrepared() {
return isPrepared;
}

/**
* 忽略isFirstLoad的值,强制刷新数据,但仍要Visible & Prepared
*/
public void setForceLoad(boolean forceLoad) {
this.forceLoad = forceLoad;
}

public boolean isFirstLoad() {
return isFirstLoad;
}

public boolean isFragmentVisible() {
return isFragmentVisible;
}

public String getTitle() {
if (null == fragmentTitle) {
setDefaultFragmentTitle(null);
}
return TextUtils.isEmpty(fragmentTitle) ? "" : fragmentTitle;
}

public void setTitle(String title) {
fragmentTitle = title;
}

/**
* 设置fragment的Title直接调用 {@link BaseFragment#setTitle(String)},若不显示该title 可以不做处理
*
* @param title 一般用于显示在TabLayout的标题
*/
protected abstract void setDefaultFragmentTitle(String title);
}

参考:
LazyFragment

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器