首先给个别人写的比较好用的封装,可实现懒加载并且保证数据只加载一次。
public abstract class BasePageFragment extends Fragment {
protected boolean isViewInitiated;
protected boolean isVisibleToUser;
protected boolean isDataInitiated;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
isViewInitiated = true;
prepareFetchData();
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
this.isVisibleToUser = isVisibleToUser;
prepareFetchData();
}
public abstract void fetchData();
public boolean prepareFetchData() {
return prepareFetchData(false);
}
public boolean prepareFetchData(boolean forceUpdate) {
/**
* 当前UI可见,并且fragment已经初始化完毕,如果网络数据未加载,那么请求数据,或者需要强制刷新页面,那么也去请求数据,
* Fragment只刷新一次,这个问题只要手动调用prepareFetchData(),传true即可强制刷新了
*/
if (isVisibleToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) {
fetchData();
isDataInitiated = true;
return true;
}
return false;
}
}
而今天主要讨论的是一个有趣的点,那就是FragmentPagerAdapter在做销毁处理时的特点(因为我在使用这个基类的时候发现我每次在多个滑动页情况下,返回过来我的页面数据还能存在,可是不应该被销毁了吗?)。我们知道普通的adapter在做销毁的时候会把整个view销毁掉(前提是你在destroyItem中做了处理),当然FragmentPagerAdapter也做了销毁处理,不过这里要注意的是,它销毁的仅仅只是当前的view而已,注意“而已”!!!看源码
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
+ " v=" + ((Fragment)object).getView());
mCurTransaction.detach((Fragment)object);
}
注意这里的最后一行代码的detach方法,那么它做了什么呢?继续源码
/**
* Detach the given fragment from the UI. This is the same state as
* when it is put on the back stack: the fragment is removed from
* the UI, however its state is still being actively managed by the
* fragment manager. When going into this state its view hierarchy
* is destroyed.
*
* @param fragment The fragment to be detached.
*
* @return Returns the same FragmentTransaction instance.
*/
public abstract FragmentTransaction detach(Fragment fragment);
看注释我们注意这句话:
however its state is still being actively managed by the fragment manager
它的意思是这个fragment在管理器中始终处于活跃状态,也就是说里面定义的变量什么的都还是存在的,并不会被销毁。所以当你下次回来的时候这些变量依然可以被使用,所以变量的初始化(比如从网络拉取的数据)应该放在封装类的抽象方法中做,这样第二次回来的时候以前的数据是可以被重用。
------------------------------------------------分割线------------------------------------------------------
再来详细说说FragmentPagerAdapter这个类的一些特点吧,这里主要探究的是它的生成特点(销毁的上面说过了)看源码:
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
这里我们看到
第3行代码,首先判断mCurTransaction是否为空。
第7行代码,获取当前的id号,接下来构造name,这个name主要作为一个tag标记丢给FragmentManager使用。
第11行代码,通过findFragmentByTag(name)获取fragment并判断是否为空。
第14行代码,如果不为空则直接通过attach(与detach方法对应)方法绘制fragment展现到屏幕上。
第16行代码,如果为空,则调用getItem方法,注意这个方法就是我们在继承FragmentPagerAdapter方法是重写的那个重要方法。然后通过add方法把这个fragment放到fragment管理器中,这里我们可以思考一个点,这个fragment管理器是通过构造函数传进来的,那么我们在外部是否也可以获取到这个fragment呢?
好了,关键代码分析完了,从代码可以看出来,其实这些frgment本身已经达到了很好的重用效果,而它们在滑动过程中的创建销毁其实只是针对view进行的,从这一点看,很多人在外部利用一个list来维护fragment的做法并不可取,因为源码通过fragment管理器已经做到了很好的管理。如果你不信,可以在if判断中打断点试一试,只有第一次创建的时候会进入else进而调用getItem方法,之后,都直接进入if语句执行。