PagerAdapter、FragmentPagerAdapter和FragmentStatePagerAdapter的关系

原创 2013年12月04日 14:12:31

ViewPager

ViewPager 如其名所述,是负责翻页的一个 View。准确说是一个 ViewGroup,包含多个 View 页,在手指横向滑动屏幕时,其负责对 View 进行切换。为了生成这些 View 页,需要提供一个 PagerAdapter 来进行和数据绑定以及生成最终的 View 页。

PagerAdapter

PageAdapter 是 ViewPager 的支持者,ViewPager 将调用它来取得所需显示的页,而 PageAdapter 也会在数据变化时,通知 ViewPager。这个类也是FragmentPagerAdapter 以及 FragmentStatePagerAdapter 的基类。如果继承自该类,至少需要实现 instantiateItem(), destroyItem(), getCount() 以及 isViewFromObject()。

  • getItemPosition()
    • 该函数用以返回给定对象的位置,给定对象是由 instantiateItem() 的返回值。
    • 在 ViewPager.dataSetChanged() 中将对该函数的返回值进行判断,以决定是否最终触发 PagerAdapter.instantiateItem() 函数。
    • 在 PagerAdapter 中的实现是直接传回 POSITION_UNCHANGED。如果该函数不被重载,则会一直返回 POSITION_UNCHANGED,从而导致 ViewPager.dataSetChanged() 被调用时,认为不必触发 PagerAdapter.instantiateItem()。很多人因为没有重载该函数,而导致调用
       PagerAdapter.notifyDataSetChanged() 后,什么都没有发生。
  • instantiateItem()
    • 在每次 ViewPager 需要一个用以显示的 Object 的时候,该函数都会被 ViewPager.addNewItem() 调用。
  • notifyDataSetChanged()
    • 在数据集发生变化的时候,一般 Activity 会调用 PagerAdapter.notifyDataSetChanged(),以通知 PagerAdapter,而 PagerAdapter 则会通知在自己这里注册过的所有 DataSetObserver。其中之一就是在 ViewPager.setAdapter() 中注册过的 PageObserver。PageObserver 则进而调用 ViewPager.dataSetChanged(),从而导致 ViewPager 开始触发更新其内含 View 的操作。

FragmentPagerAdapter

FragmentPagerAdapter 继承自 PagerAdapter。相比通用的 PagerAdapter,该类更专注于每一页均为 Fragment 的情况。如文档所述,该类内的每一个生成的 Fragment 都将保存在内存之中,因此适用于那些相对静态的页,数量也比较少的那种;如果需要处理有很多页,并且数据动态性较大、占用内存较多的情况,应该使用FragmentStatePagerAdapter。FragmentPagerAdapter 重载实现了几个必须的函数,因此来自 PagerAdapter 的函数,我们只需要实现 getCount(),即可。且,由于 FragmentPagerAdapter.instantiateItem() 的实现中,调用了一个新增的虚函数 getItem(),因此,我们还至少需要实现一个 getItem()。因此,总体上来说,相对于继承自 PagerAdapter,更方便一些。
  • getItem()
    • 该类中新增的一个虚函数。函数的目的为生成新的 Fragment 对象。重载该函数时需要注意这一点。在需要时,该函数将被 instantiateItem() 所调用。
    • 如果需要向 Fragment 对象传递相对静态的数据时,我们一般通过 Fragment.setArguments() 来进行,这部分代码应当放到 getItem()。它们只会在新生成 Fragment 对象时执行一遍。
    • 如果需要在生成 Fragment 对象后,将数据集里面一些动态的数据传递给该 Fragment,那么,这部分代码不适合放到 getItem() 中。因为当数据集发生变化时,往往对应的 Fragment 已经生成,如果传递数据部分代码放到了 getItem() 中,这部分代码将不会被调用。这也是为什么很多人发现调用 PagerAdapter.notifyDataSetChanged() 后,getItem() 没有被调用的一个原因。
  • instantiateItem()
    • 函数中判断一下要生成的 Fragment 是否已经生成过了,如果生成过了,就使用旧的,旧的将被 Fragment.attach();如果没有,就调用 getItem() 生成一个新的新的对象将被 FragmentTransation.add()
    • FragmentPagerAdapter 会将所有生成的 Fragment 对象通过 FragmentManager 保存起来备用,以后需要该 Fragment 时,都会从 FragmentManager 读取,而不会再次调用 getItem() 方法
    • 如果需要在生成 Fragment 对象后,将数据集中的一些数据传递给该 Fragment,这部分代码应该放到这个函数的重载里。在我们继承的子类中,重载该函数,并调用 FragmentPagerAdapter.instantiateItem() 取得该函数返回 Fragment 对象,然后,我们该 Fragment 对象中对应的方法,将数据传递过去,然后返回该对象。
    • 否则,如果将这部分传递数据的代码放到 getItem()中,在 PagerAdapter.notifyDataSetChanged() 后,这部分数据设置代码将不会被调用。
  • destroyItem()
    • 该函数被调用后,会对 Fragment 进行 FragmentTransaction.detach()。这里不是 remove(),只是 detach(),因此 Fragment 还在 FragmentManager 管理中,Fragment 所占用的资源不会被释放。

FragmentStatePagerAdapter

FragmentStatePagerAdapter 和前面的 FragmentPagerAdapter 一样,是继承子 PagerAdapter。但是,和 FragmentPagerAdapter 不一样的是,正如其类名中的 'State' 所表明的含义一样,该 PagerAdapter 的实现将只保留当前页面,当页面离开视线后,就会被消除,释放其资源;而在页面需要显示时,生成新的页面(就像 ListView 的实现一样)。这么实现的好处就是当拥有大量的页面时,不必在内存中占用大量的内存。
  • getItem()
    • 一个该类中新增的虚函数。
    • 函数的目的为生成新的 Fragment 对象。
    • Fragment.setArguments() 这种只会在新建 Fragment 时执行一次的参数传递代码,可以放在这里。
    • 由于 FragmentStatePagerAdapter.instantiateItem() 在大多数情况下,都将调用 getItem() 来生成新的对象,因此如果在该函数中放置与数据集相关的 setter 代码,基本上都可以在 instantiateItem() 被调用时执行,但这和设计意图不符。毕竟还有部分可能是不会调用 getItem() 的。因此这部分代码应该放到 instantiateItem() 中。
  • instantiateItem()
    • 除非碰到 FragmentManager 刚好从 SavedState 中恢复了对应的 Fragment 的情况外,该函数将会调用 getItem() 函数,生成新的 Fragment 对象。新的对象将被 FragmentTransaction.add()。
    • FragmentStatePagerAdapter 就是通过这种方式,每次都创建一个新的 Fragment,而在不用后就立刻释放其资源,来达到节省内存占用的目的的。
  • destroyItem()

ViewPager中切换及滑动切换Fragment数据保存状态讲解

最近工作中遇到了一个很棘手的问题,就是Viewpager中加载Fragment后,来回切换都会重新加载一遍数据,很浪费流量;查找了一些资料,总结一下主要就是FragmentPagerAdapter会把...
  • w372426096
  • w372426096
  • 2015年11月20日 20:06
  • 4415

ViewPager设置完FragmentPagerAdapter后动态的进行增加删除Fragment

很多新闻类的App会有增加删除频道功能,也就是在ViewPager中动态的增加删除Fragment。标准的代码为public class NewsFragmentPagerAdapter extend...
  • a516972602
  • a516972602
  • 2016年12月12日 21:45
  • 1872

关于FragmentPagerAdapter通知数据改变不刷新的问题

FragmentPagerAdapter刷新fragment最完美解决方案     先感谢kingjxl2006的博客文章《Android FragmentPagerAdapter数据刷新n...
  • u012504392
  • u012504392
  • 2016年12月03日 14:07
  • 320

ViewPager详解(四)填充Fragment和懒加载

ViewPager详解(三)Fragment的填充和懒加载实现个人主页 Demo下载地址效果图一、ViewPager基础学习请上传送门ViewPager详解(一)简单介绍和使用 ViewPager...
  • u013443865
  • u013443865
  • 2016年10月10日 18:28
  • 692

Android FragmentPagerAdapter数据刷新notifyDataSetChanged没效果研究或不执行OnCreatView方法导致界面不刷新

今天遇到一个问题是Fragment+ViewPager搭配使用的时候,页面刷新不执行OnCreateView方法到时,数据是有刷新了,但是UI界面没有刷新,还是原来的数据显示。 下面先说说我项目中的...
  • jiang547860818
  • jiang547860818
  • 2017年01月12日 17:29
  • 1543

关于Viewpager中的Fragment 滑动时保存状态的问题

之前遇到了在ViewPager中使用Fragment的情况,结果遇到了一个问题就是当viewPager划过去,再滑动回来后之前的fragment又回到了初始化的状态。所以就研究了一下。网上搜了一下,大...
  • guo807015563
  • guo807015563
  • 2014年12月22日 17:04
  • 6218

关于fragmentPagerAdapter的冲突问题

fragmentPagerAdapter是继承了PagerAdapter,这个类的作用就是用于滑动跳转Fragment,但是这个类是V4包里独有的, android app包里并没有这个类,那么问题...
  • ghdmao
  • ghdmao
  • 2016年06月16日 10:04
  • 1103

【Android进阶】关于PagerAdapter的使用方法的总结

PagerAdapter简介 PagerAdapter是android.support.v4包中的类,它的子类有FragmentPagerAdapter, FragmentStatePagerA...
  • bz419927089
  • bz419927089
  • 2014年03月30日 10:59
  • 18702

解决fragment的子fragment中viewpager里面的fragment不销毁 反复创建问题

苦苦研究了很久, 写的广播回调 为什么没用 真的是内存泄露吗? 为什么 destoryItem都不走,又怎么走注销广播的方法,但是非常烦躁,结果 放弃使用广播 实现异步通讯 。用eventbus,但是...
  • u010042660
  • u010042660
  • 2016年09月26日 14:01
  • 3311

Fragment嵌套ViewPager+Fragment使用FragmentStatePagerAdapter报错,哪位大神帮我解决这个问题

Fragment嵌套使用时的bug情景:外层使用了Fragment,在Fragment内部使用了ViewPager,ViewPager内部的每一个页面又绑定了一个Fragment问题:内部Fragme...
  • Android_Study_OK
  • Android_Study_OK
  • 2016年02月01日 14:51
  • 1465
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:PagerAdapter、FragmentPagerAdapter和FragmentStatePagerAdapter的关系
举报原因:
原因补充:

(最多只允许输入30个字)