转载:http://blog.csdn.net/dreamzml/article/details/9951577

ViewPager

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

    • ViewPager 通过 setAdapter() 来建立与 PagerAdapter 的联系。这个联系是双向的,一方面,ViewPager 会拥有 PagerAdapter 对象,从而可以在需要时调用 PagerAdapter 的方法;另一方面,ViewPager 会在 setAdapter() 中调用 PagerAdapter 的 registerDataSetObserver() 方法,注册一个自己生成的 PagerObserver 对象,从而在 PagerAdapter 有所需要时(如 notifyDataSetChanged() 或 notifyDataSetInvalidated() 时),可以调用 Observer 的 onChanged() 或 onInvalidated() 方法,从而实现 PagerAdapter 向 ViewPager 方向发送信息。
  • dataSetChanged()
    • 在 PagerObserver.onChanged(),以及 PagerObserver.onInvalide() 中被调用。因此当 PagerAdapter.notifyDataSetChanged() 被触发时,ViewPager.dataSetChanged() 也可以被触发。该函数将使用 getItemPosition() 的返回值来进行判断,如果为 POSITION_UNCHANGED,则什么都不做;如果为 POSITION_NONE,则调用 PagerAdapter.destroyItem() 来去掉该对象,并设置为需要刷新 (needPopulate = true) 以便触发 PagerAdapter.instantiateItem() 来生成新的对象。

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()
    • 将 Fragment 移除,即调用 FragmentTransaction.remove(),并释放其资源。

转载---ViewPager,PagerAdapter,FragmentPagerAdapter和FragmentStatePagerAdapter的分析对比的更多相关文章

  1. 【Android界面实现】FragmentPagerAdapter与FragmentStatePagerAdapter使用详解与区别

    转载请注明出处: http://blog.csdn.net/zhaokaiqiang1992 FragmentPagerAdapter是android-support-v4支持包里面出现的一个新的适配 ...

  2. FragmentPagerAdapter与FragmentStatePagerAdapter区别

    在一个 Android 应用中,我使用 FragmentPagerAdapter 来处理多 Fragment 页面的横向滑动.不过我碰到了一个问题,即当 Fragment 对应的数据集发生改变时,我希 ...

  3. 109、FragmentPagerAdapter与FragmentStatePagerAdapter区别

    x 在一个 Android 应用中,我使用 FragmentPagerAdapter 来处理多 Fragment 页面的横向滑动.不过我碰到了一个问题,即当 Fragment 对应的数据集发生改变时, ...

  4. FragmentPagerAdapter 与 FragmentStatePagerAdapter的区别。通过验证证明的。

    在一个 Android 应用中,我使用 FragmentPagerAdapter 来处理多 Fragment 页面的横向滑动.不过我碰到了一个问题,即当 Fragment 对应的数据集发生改变时,我希 ...

  5. [转][Android]FragmentPagerAdapter与FragmentStatePagerAdapter使用详解与区别

    原文链接:http://blog.csdn.net/zhaokaiqiang1992 FragmentPagerAdapter是android-support-v4支持包里面出现的一个新的适配器,继承 ...

  6. Android ViewPager PagerAdapter 图片轮播

    ViewPager类直接继承了ViewGroup类,所有它是一个容器类,可以在其中添加其他的View类. ViewPager类需要一个PagerAdapter适配器类给它提供数据. ViewPager ...

  7. FragmentPagerAdapter和FragmentStatePagerAdapter的差别

    ViewPager同意用户通过左右滑动显示不同页面的数据.而这些页面须要PagerAdapter管理. 经常使用的有FragmentPagerAdapter和FragmentStatePagerAda ...

  8. FragmentPagerAdapter与FragmentStatePagerAdapter差异

    平常使用的FragmentPagerAdapter和FragmentStatePagerAdapter来自android.support.v4.app包用来构建ViewPager. FragmentP ...

  9. Android实战简易教程-第三十四枪(基于ViewPager和FragmentPagerAdapter实现滑动通用Tab)

    上一段时间写过一篇文章<基于ViewPager实现微信页面切换效果> 里面实现了相似微信Tab的页面.可是这样的实现方法有个问题.就是以后全部的代码逻辑都必须在MainActivity中实 ...

随机推荐

  1. Boot 44b0x by uboot

    1. Creat a branch from tag v2013.10-rc4 2. Build it: make B2 Install NFS service for Ubuntu 12.04 1. ...

  2. winform窗体之间通过 windows API SendMessage函数传值

    -----------------------------------------------------------‘接收窗体’代码.cs------------------------------ ...

  3. C++设计模式-Command命令模式

    Command命令模式作用:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤销的操作. 由于“行为请求者”与“行为实现者”的紧耦合,使用命令模式 ...

  4. OpenGL ES(一.概念)

    OpenGL ES是以手持和嵌入式设备为目标的高级3D图形应用程序编程接口,主要的支持平台是iOS,Android,Linux和Windows 1.顶点着色器 他可以用于通过矩阵变换位置,计算照明公式 ...

  5. Nginx 502错误触发条件与解决办法汇总(转载)

    一些运行在Nginx上的网站有时候会出现“502 Bad Gateway”错误,有些时候甚至频繁的出现.有些站长是在刚刚转移到Nginx之后就出现了这个问题,所以经常会怀疑这是不是Nginx的问题,但 ...

  6. 思考方式--SMART原则

    如果你对项目管理.系统架构有兴趣,请加微信订阅号"softjg",加入这个PM.架构师的大家庭 万事开头于你目标的设定,如果开始走错了,那么后面的路将会更加的错误,甚至于更加的努力 ...

  7. hadoop namenpde机制

    1:通过查看hadoop的临时目录,看到有fsimage和edit文件 2:fsimage时namenode的元数据内存镜像文件,edit文件时hadoop客户端的操作记录, edit_inproce ...

  8. ACM知识点

    基础算法 高精 模拟 分治 贪心 排序 DFS 迭代加深搜索 BFS 双向BFS 动态规划 DAG上DP 树上DP 线性DP 图算法 最短路 FLYD DJATL BF 最大流 Dinic ISAP ...

  9. SpringBoot和数据库连接

    就像单机Java应用程序一样,和数据库连接需要DataSource,然后生成到数据库的Connection再进行数据库操作 SpringBoot和原生的JDBC 先看SpringBoot项目源码 从上 ...

  10. Debian7下lnmp+gunicorn部署Django运行环境

    首先安装lnmp,安装方法见lnmp.org wget -c http://soft.vpser.net/lnmp/lnmp1.3-full.tar.gz && tar zxf lnm ...