前言#
之前的Fragment系列我以为已经写了FragmentPagerAdapter,结果现在才发现我给忘记了,所以来给FragmentPagerAdapter补一发。
正文#
什么是FragmentPagerAdapter ?
FragmentPagerAdapter是support.v4包中提供的直接添加Fragment的适配器,主要是为ViewPager服务的,他自身有非常强大的Fragment管理机制,自动去添加移除Fragment,让开发更加的简单。
例如之前的博客中,其中截取一段代码:
// 从容器通过标签获取相同类型的Fragment
oneFragment = fm.findFragmentByTag("OneFragment");
// 判断是否为空
if (oneFragment == null){
oneFragment = new OneFragment();
}
// 判断是否添加这个fragment对象是否已经添加到容器中
// 如果已经添加过了,就show,如果没有添加就add
if (oneFragment.isAdded()){
transaction.show(oneFragment);
}else{
transaction.add(R.id.fragment_container,oneFragment, "OneFragment");
}
为了防止重复的Fragment出现,必须要检查容器中是否已经添加,简单但是很繁琐,但是FragmentPagerAdapter内部已经实现,完全不需要我们自己再去操这份心。
但是如果使用方法有问题,就无法发挥出FragmentPagerAdapter的作用,反而会留下一个巨大的内存隐患,例如看下面一段代码:
/**
* FragmentPagerAdapter 实现类
*/
private FragmentPagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
private List fragments;
@Override
public Object instantiateItem(ViewGroup container, int position) {
return fragments.get(position);
}
@Override
public Fragment getItem(int position) {
return new TestFragment();
}
@Override
public int getCount() {
return fragments.size();
}
};
首先来分析一下上面的代码,乍看起来没什么问题,因为如果熟悉使用PagerAdapter的缘故,有些朋友会条件反射的去重写instantiateItem()这个方法,并且按照PagerAdapter的思路进行了修改。那么会出现什么问题呢??
那就是内存溢出,在FragmentPagerAdapter中,每一次显示某一个Fragment的时候,都会调用instantiateItem()来获取想要的Fragment,如果一不小心重写不当,就会慢慢的添加多个重复的Framgent,最终导致内存溢出。
所以FragmentPagerAdapter如果不是有足够的重要的原因,不要重写这个方法,如果功能逻辑上需要有一点修改,也要调用super方法:
@Override
public Object instantiateItem(ViewGroup container, int position) {
TestFragment fragment = (TestFragment) super.instantiateItem(container,position);
...
return fragment;
}
那么这个getItem()是起到了什么作用呢???
getItem()方法主要是给instantiateItem()起到了辅助作用,在instantiateItem()方法中,首先回去容器中寻找,是否已经添加了指定的Fragment,如果为空,就会去调用getItem()去创建一个,所以在getItem()方法中,只要返回一个新的Fragment就可以了,这也是为什么FragmentPagerAdapter默认只让我们实现getItem()和getCount() 这两个方法。
那么关于创建新的Fragment,除了new以外,还可以通过反射去创建,例如:
@Override
public Fragment getItem(int position) {
Bundle bundle = new Bundle();
bundle.putInt("position", position);
return Fragment.instantiate(MainActivity.this,TestFragment.class.getName(), bundle);
}
三个参数一看就明白,第一个是一个上下文Context,第二个是反射的类名,第三个是bundle信息,可以通过getArguments()获得。
总结#
其实到这里这篇博客就该结束了,没有讲什么特别高深的技术,主要是讲FragmentPagerAdapter开发中需要注意的坑,不过坑是我们自己一不小心挖的。
希望我的总结能对大家有所帮助,具体一些FragmentPagerAdapter的内部实现细节以及源码,网上也有很多资料进行了讲解,我这里仅仅是描述了一个大概的思路,想要深入研究的朋友,可以自己去搜索一下。