ViewPager是android扩展包v4包中的类,这个类可以让用户左右切换当前的view
1)ViewPager类直接继承了ViewGroup类,所有它是一个容器类,可以在其中添加其他的view类。
2)ViewPager类需要一个PagerAdapter适配器类给它提供数据,适用于View。
3)ViewPager经常和Fragment一起使用,并且提供了专门的FragmentPagerAdapter和FragmentStatePagerAdapter类供Fragment中的ViewPager使用,注意使用的是v4的Fragment。
//PagerAdapter最基本的使用,必须实现四个方法
public class AdapterViewpager extends PagerAdapter {
private List mViewList;
public AdapterViewpager(List mViewList) {
this.mViewList = mViewList;
}
@Override
public int getCount() {//必须实现
return mViewList.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {//必须实现,判断容器里的View是否与一个key值相关联,比如说例如Fragment+ViewPager的处理,每个页面都由它是对应的Fragment来呈现,但ViewPager并不是直接与View关联,而是关联一个key。
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {//必须实现,父类未实例化
container.addView(mViewList.get(position));
return mViewList.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {//必须实现,父类未实例化
container.removeView(mViewList.get(position));
}
}
FragmentStatePagerAdapter的实现和FragmentPagerAdapter的实现一样:
public class AdapterFragment extends FragmentPagerAdapter {
private List mFragments;
public AdapterFragment(FragmentManager fm, List mFragments) {
super(fm);
this.mFragments = mFragments;
}
@Override
public Fragment getItem(int position) {//必须实现
return mFragments.get(position);
}
@Override
public int getCount() {//必须实现
return mFragments.size();
}
@Override
public CharSequence getPageTitle(int position) {//选择性实现
return mFragments.get(position).getClass().getSimpleName();
}
}
FragmentStatePagerAdapter与FragmentPagerAdapter的不同:
FragmentStatePagerAdapter类名中的“state”表明:在销毁fragment时,调用remove(Fragment)将fragment从FragmentManager中彻底移除。可在fragment的onSaveInstanceState(Bundle)方法中保存fragment的状态信息。在用户切换回来时,保存的实例状态可用来恢复生成新的fragment。当页面离开视线后,就会被消除,释放其资源;而在页面需要显示时,生成新的页面(就像 ListView 的实现一样)。这么实现的好处就是当拥有大量的页面时,不必在内存中占用大量的内存。
对于不再需要的fragment,FragmentPagerAdapter会调用detach(Fragment)方法来处理,而不是remove(Fragment)。所以FragmentPagerAdapter只是销毁了fragment的视图,fragment实例还保留在FragmentManager中。因此,FragmentPagerAdapter创建的fragment永远不会被销毁。
通过Fragment fragment = mFragmentManager.findFragmentByTag(name)进行旧的Fragment的读取.。
FragmentStatePagerAdapter在instantiateItem方法中,创建新Fragment后,读取对应Fragment状态对其进行初始化设置,并且只使用到add方法;FragmentPagerAdapter使用Transaction设置Tag进行add。
FragmentStatePagerAdapter在destroyItem方法中,销毁Fragment时,保存其Fragment状态,并且使用remove方法移除Fragment,同时设置mFragments中对应位置为空。
FragmentPagerAdapter销毁时使用的是mCurTransaction.detach((Fragment)object);//并没有真正释放fragment对象只是detach。
FragmentStatePagerAdapter重载了saveState方法和restoreState方法,在其中对于Fragment实例列表和Fragment状态列表进行保存和读取。
FragmentStatePagerAdapter源码:
@Override
public Object instantiateItem(ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
return f;
}
}
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
Fragment fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
if (mSavedState.size() > position) {
Fragment.SavedState fss = mSavedState.get(position);
if (fss != null) {
fragment.setInitialSavedState(fss);
}
}
while (mFragments.size() <= position) {
mFragments.add(null);
}
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
mFragments.set(position, fragment);
mCurTransaction.add(container.getId(), fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object;
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
+ " v=" + ((Fragment)object).getView());
while (mSavedState.size() <= position) {
mSavedState.add(null);
}
mSavedState.set(position, fragment.isAdded()
? mFragmentManager.saveFragmentInstanceState(fragment) : null);
mFragments.set(position, null);
mCurTransaction.remove(fragment);
}
FragmentPagerAdapter源码:
@SuppressWarnings("ReferenceEquality")
@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;
}
@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);
}
FragmentPagerAdapter中的fragment实例在destroyItem的时候并没有真正释放fragment对象只是detach,所以FragmentPagerAdapter消耗更多的内存,
带来的好处就是效率更高一些。所以得出这样的结论:FragmentPagerAdapter适用于页面比较少的情况,FragmentStatePagerAdapter适用于页面比较多的情况,
因此不同的场合选择合适的适配器才是正确的做法。
FragmentPagerAdapter在切换时的效果。可见最后调用的只是onDestroyView,重新加载也不会执行onCreate方法,因此内存占用比较高:
FragmentStatePagerAdapter在切换时的效果,最终执行了onDestroy()和onDetach(),重新加载会执行onCreate方法,其缓存个数跟ViewPager的viewPager.setOffscreenPageLimit()有关,
默认是1。setOffscreenPageLimit设置的值是表示左右各缓存N个。
Activity与Fragment配合使用时经常遇到一个问题,当activity被销毁时重建,其上的view的状态和数据会被保存,以便数据恢复。
Activity已经被销毁,而Fragment还在,最好的解决办法就是:不保存因意外导致的状态和View,防止Activity重新创建时Fragment状态位置混乱。
@Override
public voidonSaveInstanceState(Bundle outState) {
//将super调用取消即可,表明当意外(比如系统内存吃紧将应用杀死)发生我不需要保存Fragmentde状态和数据等
//super.onSaveInstanceState(outState);
}