Fragment专辑(五):神奇的FragmentPagerAdapter

前言#

之前的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的内部实现细节以及源码,网上也有很多资料进行了讲解,我这里仅仅是描述了一个大概的思路,想要深入研究的朋友,可以自己去搜索一下。

你可能感兴趣的:(Fragment专辑(五):神奇的FragmentPagerAdapter)