在开发中经常用的Fragment+ViewPager的情况,但是viewPager的缓存机制导致至少会提前加载一个邻近的Fragment,导致数据重复加载。此时的解决办法是写一个基类BaseLasyFragment来处理,具体实现如下:
public abstract class BaseLazyFragment extends Fragment {
/**
* Log tag
*/
protected static String TAG_LOG = null;
/**
* context
*/
protected Context mContext = null;
/**
* 视图是否已经初初始化
*/
protected boolean isInit = false;
protected boolean isLoad = false;
protected final String TAG = "LazyLoadFragment";
private View view;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mContext = activity;
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if (getContentViewLayoutID() != 0) {
view = inflater.inflate(getContentViewLayoutID(), container, false);
} else {
view = super.onCreateView(inflater, container, savedInstanceState);
}
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initViewsAndEvents(savedInstanceState);
isInit = true;
/**初始化的时候去加载数据**/
isCanLoadData();
}
@Override
public void onDestroyView() {
super.onDestroyView();
isInit = false;
isLoad = false;
}
@Override
public void onDetach() {
super.onDetach();
// for bug ---> java.lang.IllegalStateException: Activity has been destroyed
try {
Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
childFragmentManager.setAccessible(true);
childFragmentManager.set(this, null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* 视图是否已经对用户可见,系统的方法
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
isCanLoadData();
}
/**
* 是否可以加载数据
* 可以加载数据的条件:
* 1.视图已经初始化
* 2.视图对用户可见
*/
private void isCanLoadData() {
if (!isInit) {
return;
}
if (getUserVisibleHint()) {
lazyLoad();
isLoad = true;
} else {
if (isLoad) {
stopLoad();
}
}
}
/**
* 当视图初始化并且对用户可见的时候去真正的加载数据
*/
protected abstract void lazyLoad();
/**
* 当视图已经对用户不可见并且加载过数据,如果需要在切换到其他页面时停止加载数据,可以调用此方法
*/
public void stopLoad() {
}
/**
* bind layout resource file
*
* @return id of layout resource
*/
protected abstract int getContentViewLayoutID();
/**
* when event comming
*
* @param eventCenter
*/
protected abstract void onHandleEventMessage(EventCenter eventCenter);
/**
* init all views and add events
*/
protected abstract void initViewsAndEvents(Bundle savedInstanceState);
}
然后在自定义Fragment继承BaseLasyFragment ,复写lasyLoad()方法即可,在此方法中实现展示页面时数据请求的操作,能保证只有在展示页面的时候才进行数据请求。
如果想在Fragment隐藏的时候取消数据请求,可以复写stopLoad()方法进行处理。
有时候需要每次在Fragment页面展示的时候添加一个Fragment页面列表,第二次进入添加列表的时候,会导致已经添加过的列表还存在,不管是调用viewPager的removeAllViews()还是清空adapter,都无作用,原因是FragmentPagerAdatper添加过的Fragment都在内存中缓存了,除非退出APP,否则一直存在,此时解决办法是改用继承FragmentStatePagerAdapter,并且复写以下方法,然后再调用viewPager的removeAllViews()和adapter的notifyDataSetChanged(当然需要清空列表)即可
public int getItemPosition(Object item) {
return POSITION_NONE;
}
结合上面的懒加载基类,可以在stopLoad()回调中进行清空缓存操作。切记不要放在 lasyLoad()方法里,因为每次新增Fragment的时候,lasyLoad()是拿不到之前隐藏掉的Fragment中的数据的,所以在隐藏的时候进行清空缓存是可以保证清楚的干干净净的。