浅谈viewpager+fragment缓存问题的优化

作者: LeoYe168 | 来源:发表于2016-07-04 19:21 被阅读5482次

    问题是这样的,项目中有 用到tablayout+viewpager+fragment这个顶部导航模块,切换的tab大概有十个,除了第一tab的fragment,其他tab的fragment都是同一个class只是数据不同。因为是电商的app,所以图片特别多等等原因的占用内存比较大,再加上这块fragment对象多因此这块的优化需求就有了。

    ps:公司项目原因,不便传截图。


    项目中最初是这样的,废话不多说直接上代码

    @Override

    public FragmentgetItem(intposition) {

    if(position ==0) {

    return newHomeFragment();

    }else{

    returnOtherCategoryFragment.newInstance();

    }

    }

    public static OtherCategoryFragment newInstance(intid,String categoryName) {

    OtherCategoryFragment otherCategoryFragment =newOtherCategoryFragment();

    otherCategoryFragment.categoryId= id;

    otherCategoryFragment.categoryName= categoryName;

    returnotherCategoryFragment;

    }

    viewpageradapter中getitem中每次都是调用fragment的newInstance方法,然而newInstance方法都是直接new一个对象。我的天啊,这能忍,岂不是每次切换都会new对象的。于是我开始了第一次优化:


    @Override

    public Fragment getItem(int position) {       

    Fragment fragment;if(fragments.size() <= position) {

    if(position ==0) {               

       fragment = PrimeHomeFragment.newInstance();           

    }else{               

       fragment = PrimeOtherCategoryFragment.newInstance(categories.get(position).id,      position);            }           

       fragments.add(fragment);        }else{           

       fragment = fragments.get(position);       

    }

    returnfragment;   

    }

    其实我就是加了个ArrayList fragments来保存new出来的fragment,当第二次使用该fragment时候直接取出来不再是油重新new一个对象。眼尖的人或许看出来了这种做法too young,因为viewpager会自己管理fragments,默认缓存(预加载)DEFAULT_OFFSCREEN_PAGES =1参赛,其他页面fragment会自动finish掉,所以我用list保存fragment并没什么卵用的,超出缓存数还是会继续new。于是开启了继续优化

    viewPager.setOffscreenPageLimit(fragmentList.size()-1);

    上面提到过viewpager会自动管理缓存的,默认为DEFAULT_OFFSCREEN_PAGES=1。那我设置全部缓存不就ok了么,嗯,问题是解决了,然而产品会杀了你,因为加载第一个页面时候把把所有页面预加载出来才会完整显示第一个页面,所以第一个页面会等很久很久。于是开始了继续优化


    @Override

    public Fragment getItem(int position) {       

    Fragment fragment;

    if(fragments.size() <= position) {

    if(position ==0) {               

    fragment = PrimeHomeFragment.newInstance();         

      }else{               

    fragment = PrimeOtherCategoryFragment.newInstance(categories.get(position).id, position);            }           

    fragments.add(fragment);        }else{            //returnPrimeOtherCategoryFragment.newInstance(categories.get(position).id);            fragment = fragments.get(position);           

    //returnfragments.get(position);        }       

    //保存Fragment       

    Bundle bundle = new Bundle();       

    bundle.putString("id",""+ position);       

    fragment.setArguments(bundle);returnfragment;   

    }@Override

    public Fragment instantiateItem(ViewGroup container, int position) {       

    Fragment fragment = (Fragment) super.instantiateItem(container,  position);        fm.beginTransaction().show(fragment).commit();

    returnfragment;    }

    @Override

    public void destroyItem(ViewGroup container, int position, Object object) {     

      // super.destroyItem(container, position, object);        fm.beginTransaction().hide(fragments.get(position)).commit();   

    }

    这种优化的基本思路是底部导航栏的思路,采用hide和show来控制。也就是第一次加载出来后,再到该fragment就通过调用show方法来显示。当然确定也就是super.destroyItem没被调用,也就是fragment对象会一直存在那,内存占用问题没很好的解决,于是再再下次优化开始


    思路:其实针对我们项目本身tab切换的fragment虽然十来个很多,可除了第一个其他的是同一个fragment只是数据不同而已。于是listview的优化思路出来了,即共用ui,切换界面其实只是刷数据而已,具体我还没去实现只有这个思路,大概列出几个注意的点:

    自己管理viewpager对fragment的new和destory管理

    自行设计fragmnet与pageradapter间的通信

    ps:有更好思路的,可以说说意见一起试试。。还有简书不能Markdown么 ?

    相关文章

      网友评论

      • 84637d1af8a2:最后的思路想来不错,但是得不偿失,除非你不需要保存每个view 的状态,但是不需要保存的话,那又没必要去那样实现,只需要每个fragment只有显示的时候才去加载数据,这样就不会出现很久才加载出来数据的问题
      • 黑饼饼饼:您好,最近在做电商方面的需求,遇到和您一样的问题,博主现在的优化做的怎么样了呢?是否能指点一二?不胜感激
        LeoYe168:@黑饼饼饼 这个你恐怕要在图片处理上下功夫的
        黑饼饼饼:@LeoYe168 我在用viewpager+fragment+gridview来展示商品列表信息,gridview显示2列商品信息,多图,用glide加载,在滑动列表时,图片释放不掉,发生OOM ,如果优化,能不能指点一二?谢谢
        LeoYe168:@黑饼饼饼 你具体遇到了什么问题?
      • 56c34ecae2d9:我也很郁闷这个问题, 我就5个fragment也一卡一卡的
        LeoYe168: @我是薄荷啊呀呀 做过哪些优化没呢
      • cuixbo:最后的思路不错可以尝试一下
        LeoYe168: @崔小波 理论上是可行的偶
      • 菜鸟考官:写的不错。最近也正在做新闻这种的。就是没有网络的话不知道该怎么缓存
        LeoYe168:@菜鸟考官 那是网络缓存犯愁了。一般网络框架提供缓存借口。当然你也可以用数据库自己做缓存
      • 皮球二二:你可以用setLimitOffset缓存全部之后,每次加载都加载当前页即可
        LeoYe168:@r17171709 是这个setOffscreenPageLimit ?这个方案我试过,可在我们项目不适用,因为我们有十几个fragment,第一次都new出那么多对象显然不现实
      • 我想要有你在的未来:你不想每次new出来的原因是,这样会每次去获取网络接口而造成流量使用了很多?
        LeoYe168:@我想要有你在的未来 cpu消耗也很大
        LeoYe168: @我想要有你在的未来 流量是一个方面,不停的new destory废内存,而且destory并非立马就会清掉内存
      • LeoYe168:用markdown写好了,然后简书不支持,所以排版有点乱
        皮球二二:@LeoYe168 你这个代码的格式应该变成>了,不是``` java
        LeoYe168:@LeoYe168 反正我在网页版跟App半天没找到
        alighters:@LeoYe168 支持的,只是跟一些编辑器渲染的标准不一样

      本文标题:浅谈viewpager+fragment缓存问题的优化

      本文链接:https://www.haomeiwen.com/subject/xgxhjttx.html