一、ViewPager和PagerAdapter
1、ViewPager的缓存机制
调用setOffscreenPageLimit(n ) 方法来设置缓存的页面,当前页面的相邻n个页面都会被缓存
默认的n为1,当前页面的前后1个页面默认被缓存。
2、setAdapter方法 源码
public void setAdapter(PagerAdapter adapter) {
if (mAdapter != null) {
//清除观察者
mAdapter.setViewPagerObserver(null);
//设置回调,开始更新页面
mAdapter.startUpdate(this);
for (int i = 0; i < mItems.size(); i++) {
final ViewPager.ItemInfo ii = mItems.get(i);
//清除之前页面
mAdapter.destroyItem(this, ii.position, ii.object);
}
//设置回调,完成更新
mAdapter.finishUpdate(this);
mItems.clear();
removeNonDecorViews();
//页面重置到第一个
mCurItem = 0;
//滑动到开始位置
scrollTo(0, 0);
}
final PagerAdapter oldAdapter = mAdapter;
//设置新的adapter
mAdapter = adapter;
mExpectedAdapterCount = 0;
if (mAdapter != null) {
if (mObserver == null) {
mObserver = new ViewPager.PagerObserver();
}
//设置观察者
mAdapter.setViewPagerObserver(mObserver);
mPopulatePending = false;
final boolean wasFirstLayout = mFirstLayout;
mFirstLayout = true;
//设置数据个数
mExpectedAdapterCount = mAdapter.getCount();
if (mRestoredCurItem >= 0) {
//如果需要恢复数据
mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
setCurrentItemInternal(mRestoredCurItem, false, true);
mRestoredCurItem = -1;
mRestoredAdapterState = null;
mRestoredClassLoader = null;
} else if (!wasFirstLayout) {
//如果不是第一次layout,创建或销毁页面
populate();
} else {
requestLayout();
}
}
//设置监听器
if (mAdapterChangeListener != null && oldAdapter != adapter) {
mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter);
}
}
3、PagerAdapter常用方法:
private List datas;
class MyAdapter extends PagerAdapter{
//返回当前有效视图的个数
@Override
public int getCount() {
return datas.size();
}
/**
* 该函数用来判断instantiateItem(ViewGroup, int)函数所返回来的Key与一个页面视图是否是代表的同一个视图
* 如果相同,表示是同一个view
*/
@Override
public boolean isViewFromObject(View view, Object object) {
return view==object;
}
//移除一个给定位置的页面
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
/**
* 创建指定位置的页面视图
* (1)将position位置的视图,增加到conatiner中,供其创建并显示。
* (2)返回当前的view作为此视图的key
*/
@Override
public Object instantiateItem(ViewGroup container, int position) {
TextView textView = new TextView(ImageActivity.this);
textView.setText(datas.get(position));
container.addView(textView);
return textView;
}
}
4、PagerAdapter基类
public class BasePagerAdaper extends PagerAdapter {
protected List mDateList;
protected Context mContext;
public BasePagerAdaper(Context context){
if (mDateList==null){
mDateList = new ArrayList();
}
this.mContext = context;
}
public BasePagerAdaper(Context context,List dateList) {
if (mDateList==null){
mDateList = new ArrayList();
}
this.mDateList = dateList;
this.mContext = context;
}
public void setData(List dateList){
mDateList = dateList;
notifyDataSetChanged();
}
public void addData(T t){
if (mDateList!=null){
mDateList.add(t);
notifyDataSetChanged();
}
}
@Override
public int getCount() {
if (mDateList!=null){
return mDateList.size();
}
return 0;
}
@Override
public boolean isViewFromObject(View view, Object o) {
return view == o;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
/**
* 如果T是View的子类。
* 如果不是需要重写此方法
*/
@Override
public Object instantiateItem(ViewGroup container,final int position) {
T t= mDateList.get(position);
container.addView((View)t);
return t;
}
}
二、FragmentPagerAdapter
1、部分源码
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
//获取单个条目的id
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
//根据名称获取Fragment
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
//如果Fragment已经添加到FragmentManager中,将view视图从附加到UI上
mCurTransaction.attach(fragment);
} else {
//将Fragment添加到FragmentManager中
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());
//将view视图从ui上移除,但是Fragment还是由FragmentManager维护。
mCurTransaction.detach((Fragment)object);
}
2、ViewPager左右切换:
(1)首次进入position为0的Fragment
setUserVisibleHint 参数为true,Fragment可见
首次进入时,position 为0 和1的Fragment会调用onAttach —onResume方法
(2)首次进入position为1的Fragment

创建position为2的Fragment,position为1的Fragment的setUser’VisibleHint 参数为true
(3)首次进入position为2的Fragment
position为0的Fragment 调用了onPause、onStop、onDestroyView 。没有调用onDestroy和onDetach方法,
Fragment还由FragmentManager管理。
position为3的Fragment进行创建并缓存。position为1的Fragment不可见。
(4)再次进入position为1的Fragment
position为1的Fragment没有调用onAttach、onCreate方法,只是调用onCreateView将view视图重新附加到ui上并显示。
position为3的Fragment调用onStop、onDestroyView销毁视图。Fragment还由FragmentManager管理。
3、FragmentAdapter基类:
public class BaseFragmentAdapter extends FragmentPagerAdapter {
private List fragments;
private Fragment mCurrentFragment;
public BaseFragmentAdapter(FragmentManager fm) {
super(fm);
}
public BaseFragmentAdapter(FragmentManager fm, List fragments) {
super(fm);
this.fragments = fragments;
}
public void setFragments(List fragments){
this.fragments = fragments;
notifyDataSetChanged();
}
public void addFragment(Fragment fragment){
if (fragments!=null){
fragments.add(fragment);
notifyDataSetChanged();
}
}
@Override
public Fragment getItem(int i) {
if (fragments!=null){
return fragments.get(i);
}
return null;
}
@Override
public int getCount() {
if (fragments!=null){
return fragments.size();
}
return 0;
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
mCurrentFragment = (Fragment) object;
super.setPrimaryItem(container, position, object);
}
/**
* 获取当前的Fragment
* @return
*/
public Fragment getCurrentFragment(){
return mCurrentFragment;
}
}
三、FragmentStateAdapter
1、部分源码
//保存Fragment状态信息的列表
private ArrayList mSavedState = new ArrayList();
//保存Fragment实例对象的列表
private ArrayList mFragments = new ArrayList();
@Override
public Object instantiateItem(ViewGroup container, int position) {
//获取某位置的Fragment
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);
//读取给定位置的Fragment保存的状态
if (mSavedState.size() > position) {
Fragment.SavedState fss = mSavedState.get(position);
if (fss != null) {
//用该状态对Fragment进行初始化
fragment.setInitialSavedState(fss);
}
}
while (mFragments.size() <= position) {
mFragments.add(null);
}
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
mFragments.set(position, fragment);
//添加Fragment到FragmentManager中
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);
}
//保存当前销毁的Fragment的状态
mSavedState.set(position, fragment.isAdded()
? mFragmentManager.saveFragmentInstanceState(fragment) : null);
mFragments.set(position, null);
//移除销毁的Fragment
mCurTransaction.remove(fragment);
}
(1)在instantiateItem方法中,创建Fragment,读取相应Fragment的状态,对其进行初始化,然后add 到FragmentManager中。
(2)在destoryItem方法中,销毁Fragment,保存Fragment的状态,通过remove移除Fragment。
2、ViewPager 左右切换
1)首次进入position为0的Fragment
首次进入时,position 为0 和1的Fragment会调用onAttach —onResume方法
(2)首次进入position为1的Fragment
创建position为2的Fragment,position为1的Fragment的setUser’VisibleHint 参数为true
(3)首次进入position为2的Fragment
创建position为3的Fragment,position为0的Fragment的通过onDestroy和onDetach方法进行了销毁。
(4)再次返回position为1的Fragment
重新创建了position为0的Fragment,但是saveInstanceState参数还保留着之前存储的数据。position为3的Fragment销毁。
3、基类:
public class BaseFragmentStateAdapter extends FragmentStatePagerAdapter {
private List fragments;
private Fragment mCurrentFragment;
public BaseFragmentStateAdapter(FragmentManager fm, List fragments) {
super(fm);
this.fragments = fragments;
}
public void addFragment(Fragment fragment){
if (fragments!=null){
fragments.add(fragment);
notifyDataSetChanged();
}
}
@Override
public Fragment getItem(int i) {
if (fragments!=null){
return fragments.get(i);
}
return null;
}
@Override
public int getCount() {
if (fragments!=null){
return fragments.size();
}
return 0;
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
mCurrentFragment = (Fragment) object;
super.setPrimaryItem(container, position, object);
}
//获取当前的Fragment
public Fragment getCurrentFragment(){
return mCurrentFragment;
}
}
4、总结:
FragmentPagerAdapter
每一个生成的 Fragment 都将保存在内存之中,因此适用于那些相对静态的页,数量也比较少的那种;如果需要处理有很多页,并且数据动态性较大、占用内存较多的情况,应该使用FragmentStatePagerAdapter。