原作者:炙炎gg
链接:https://www.jianshu.com/p/9eb1c379f3e7#
來源:简书
对于原文的解析在某些方面做了进一步分析,代码如下
/**
* Created by LinLin on 2018/6/6.
* 在viewpager中使用Fragment,Fragment的成员变量是不会销毁的
* <p>
* 利用Fragment的生命周期进行懒加载 ,预加载使用ViewStub代替真实View
*/
public abstract class MagicLifeLazyFragment extends Fragment
{
/**
* 根view,升格为成员变量保持不会销毁
*/
private View mRootView;
/**
* 用于回调的,用户是否可见参数,升格为成员变量保持不会销毁
*/
private boolean isVisibleToUser;
/**
* 第一次加载
*/
private boolean isFirstLoad;
/**
* view是否已经创建完毕
*/
private boolean isViewCreated;
/**
* 第一次加载的占位图
*/
private ViewStub mViewStub;
@Nullable
@Override
public final View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
{
/**
* 判断根view是否为空。
* 为空代表第一次加载;
* 不为空代表曾经加载过,这次是重复加载,因为是成员变量,不会被销毁,所以直接返回
* */
if (null != mRootView)
{
isViewCreated = true;//设为view已加载
return mRootView;
}
/**
* 第一次加载,使用占位图,使用FrameLayout作为根view,包裹一个ViewStub
* */
final Context context = inflater.getContext();
FrameLayout root = new FrameLayout(context);
mViewStub = new ViewStub(context, getResId());
root.addView(mViewStub, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
root.setLayoutParams(new ViewGroup.MarginLayoutParams(ViewGroup.MarginLayoutParams.MATCH_PARENT, ViewGroup.MarginLayoutParams.MATCH_PARENT));
mRootView = root;//作为根view
isViewCreated = true;//设为view已加载
if (isVisibleToUser)
{
realLoad();
}
return mRootView;
}
@Override
public void onDestroyView()
{
isViewCreated = false;
super.onDestroyView();
}
/**
* 关于这个方法的被回调的地方有:
* 1、FragmentPagerAdapter 的 public Object instantiateItem(ViewGroup container, int position)方法里
* if (fragment != mCurrentPrimaryItem) {
* fragment.setMenuVisibility(false);
* fragment.setUserVisibleHint(false);
* }
* 初始化的时候会设为false
* 2、 FragmentPagerAdapter 的 public void setPrimaryItem(ViewGroup container, int position, Object object) 方法里
* if (fragment != mCurrentPrimaryItem) {
* if (mCurrentPrimaryItem != null) {
* mCurrentPrimaryItem.setMenuVisibility(false);
* mCurrentPrimaryItem.setUserVisibleHint(false);
* }
* if (fragment != null) {
* fragment.setMenuVisibility(true);
* fragment.setUserVisibleHint(true);
* }
* mCurrentPrimaryItem = fragment;
* }
* 而上述方法都会被viewpager回调。
* 举个例子:有FragmentA,FragmentB,FragmentC三个,当前显示的是FragmentB
* 那么初始化顺序是 FragmentA,FragmentB,FragmentC 分别设 setUserVisibleHint(false);
* 然后选择FragmentB为当前页面,viewpager调用setPrimaryItem方法,FragmentB设 setUserVisibleHint(true);
* 由于是第一次加载所以mCurrentPrimaryItem==null,否则旧的Fragment也会设一次setUserVisibleHint(false);
* 结合Fragment的生命周期得知:当isVisibleToUser为true以及根view创建完毕即可加载数据
*/
@Override
public final void setUserVisibleHint(boolean isVisibleToUser)
{
super.setUserVisibleHint(isVisibleToUser);
this.isVisibleToUser=isVisibleToUser;
if (isViewCreated && isVisibleToUser)
{
realLoad();
}
}
/**
* 真实加载数据
* 控制只允许加载一次
*/
private void realLoad()
{
if (isFirstLoad)
{
return;
}
isFirstLoad = true;
onRealViewLoaded(mViewStub.inflate());
}
/**
* 获取真正的数据视图
*/
protected abstract int getResId();
/**
* 当视图真正加载时调用
*/
protected abstract void onRealViewLoaded(View view);
}