做景区网站建设的公司,东莞动点网络科技有限公司,建设网站思路,长春做网站优化的公司转自#xff1a;http://blog.csdn.net/dreamzml/article/details/9951577 ViewPager ViewPager 如其名所述#xff0c;是负责翻页的一个 View。准确说是一个 ViewGroup#xff0c;包含多个 View 页#xff0c;在手指横向滑动屏幕时#xff0c;其负责对 View 进行切换。为了… 转自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()并释放其资源。