在ViewPager与Fragment一起使用时,由于ViewPager的特性,Fragment会预加载,但是我们希望只在当前界面时才加载数据。
基类:
public abstract class LazyFragment extends Fragment {
//当前Fragment是否可见
protected boolean isVisible;
/**
* 在这里实现Fragment数据的缓加载.
* @param isVisibleToUser
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(getUserVisibleHint()) {
isVisible = true;
onVisible();
} else {
isVisible = false;
onInvisible();
}
}
protected void onVisible(){
lazyLoad();
}
protected abstract void lazyLoad();
protected void onInvisible(){}
}
子类Fragment:
//思想:当不可见时只inflate布局(且只inflate一次),
// 可见时去加载数据,只加载一次,滑动下一个再回来时就不去加载数据了,除非手动刷新(或者Fragment被回收)
public class MyFragment1 extends LazyFragment {
//布尔的默认值是false
// 标志位,标志已经初始化完成。(是否已经inflat布局以及findviewById了)
private boolean isPrepared;
private TextView rootView;
/**
* 是否已加载过一次数据(可能走网络),第二次就不再去请求数据了
*/
private boolean mHasLoadedDataOnce;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d("alan", "MyFragment1 oncreateView");
if (rootView == null) {
Log.d("alan", "init rootView");
rootView = new TextView(getActivity());
//... 初始化各种控件(findViewById)
isPrepared = true;
lazyLoad();
}
//因为共用一个Fragment视图,所以当前这个视图已被加载到Activity中,必须先清除后再加入Activity
ViewGroup parent = (ViewGroup) rootView.getParent();
if (parent != null) {
parent.removeView(rootView);
}
return rootView;
}
//必须先inflate过布局,才能去加载数据,注意顺序
@Override
protected void lazyLoad() {//加载数据,主要操作都在这里,三个判断条件
Log.d("alan", "isPrepared----->" + isPrepared);
if (!isPrepared || !isVisible || mHasLoadedDataOnce) {
return;
}
//虚拟一个加载网络数据的任务
new AsyncTask<Void, Void, Boolean>() {
private AlertDialog alertDialog;
@Override
protected void onPreExecute() {
super.onPreExecute();
//显示加载进度对话框
UIHelper.showDialogForLoading(getActivity(),"正在加载...",true);
}
@Override
protected Boolean doInBackground(Void... params) {
try {
Thread.sleep(2000);
//走网络
//doSomething()
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
@Override
protected void onPostExecute(Boolean isSuccess) {
if (isSuccess) {// 加载成功
UIHelper.hideDialogForLoading();
mHasLoadedDataOnce = true;//加载成功之后才算加载好了一次数据
//加载数据完成后,填充各个控件
rootView.setText(getClass().getName());
} else {
// 加载失败
UIHelper.hideDialogForLoading();
}
}
}.execute();
}
}
思想梳理:Fragment预加载时只加载布局,并且只加载一次,加载完布局并且可见时才去加载填充数据(也只做一次)。
源码
参考文章