谈谈FragmentPagerAdapter和FragmentStatePagerAdapter

来源:互联网 发布:原生js请求接口 编辑:程序博客网 时间:2024/06/04 17:52

两者区别

这两个类都是继承自PagerAdapter,只是他们的处理的方式不一样。(代码我就不贴了,大家可自行在AS上看源码)
首先是FragmentPagerAdapter,他是将已经生成的Fragment都保存下来,切换页面时如果Fragment不存在就先生成一个,如果已经存在了就直接attach这个fragment,旧Fragment只被detach掉,但不会将其移除。
然后是FragmentStatePagerAdapter,他是按需生成Fragment,根据用户设定的保存页面数量来缓存Fragment,超过的将会被移除。

使用场景

看了上面所说的两者区别,相信大家心里都比较清楚了,FragmentPagerAdapter适合使用在数量少的情况下,如首页固定的几个Fragment(如微信首页的微信,通讯录,发我,我)。FragmentStatePagerAdapter适合使用在数量多或不确定的情况下(如今日头条的新闻分类,科技,娱乐,生活等)

碰到的问题

有时可能有同学会问,使用了FragmentPagerAdapter有时会报错
java.lang.IllegalStateException: Can’t change tag of fragment PageFragment
这个问题可以追溯到FragmentPagerAdapter的缓存机制,由于他是缓存所有页面,所以每个页面都有一个唯一id对应,这个id是由方法getItemId生成

/**     * Return a unique identifier for the item at the given position.     *     * <p>The default implementation returns the given position.     * Subclasses should override this method if the positions of items can change.</p>     *     * @param position Position within this adapter     * @return Unique identifier for the item at position     */    public long getItemId(int position) {        return position;    }

默认就是用position作为id,如果同时存在多个id相同fragment就会报错,具体代码如下

private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {        //=======省略代码======        if (tag != null) {            if (fragment.mTag != null && !tag.equals(fragment.mTag)) {                throw new IllegalStateException("Can't change tag of fragment "                        + fragment + ": was " + fragment.mTag                        + " now " + tag);            }            fragment.mTag = tag;        }        //=======省略代码=======    }

什么情况下会出现这种情况?

一般我们用FragmentPagerAdapter不会重写getItemId方法,所以唯一id就是position,当adapter里的数据发生改变(即fragment数量改变了或fragment有被替换的情况),由于旧id的fragment被缓存,这就导致id一样但fragment对象不一样的情况。

怎么解决?
网上很多都说重写getItemId方法,自己生成一个唯一id(如fragment的hashcode等)来处理,这个方法看上去可行,但忽略了一种特殊情况,就是被系统回收后进行恢复的情况,恢复是会重新生成fragment的,此时由于使用hashcode,所以两个id就不一样了导致报错,除非你能设计出一个恢复的时候也是相同id的算法,否则不要使用此方法。
开头我说过FragmentPagerAdapter的使用场景,既然需求是可变的fragment列表,那为什么还要使用FragmentPagerAdapter来实现呢?所以这里只要换成FragmentStatePagerAdapter来实现即可。

阅读全文
1 0
原创粉丝点击