问题描述
最近做一个新功能,用到Viewpager内嵌Fragment的结构,由于需要做缓存,所以每次进入都会先根据缓存的标签去加载缓存数据,再去服务器请求最新的标签加载最新数据,这就需要刷新Viewpager中的Fragment,但是如果你只是用Adapter.notifyDataSetChanged()试图去更新Viewpager的adapter数据, 或者Viewpager.removeAllView()去删除Viewpager中的Fragment时,你会发现根本没有真正删除,因为你会发现Fragment中的数据并没有被内存释放,刷新后的Fragment依然在用之前的Fragment内存中的值,表现就是刷新数据重复。通过断点调试也验证了这个问题,Fragment中的变量在内存中被重用了。
解决方法
一.继承FragmentStatePagerAdapter
将Viewpager的Adapter由继承FragmentPagerAdapter改为继承FragmentStatePagerAdapter。
二.实现getItemPosition方法
@Overridepublic int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
原因
引用一下StackOverFlow上大神的解释,解释得非常清楚
The ViewPager doesn't remove your fragments with the code above because it loads several views (or fragments in your case) into memory. In addition to the visible view, it also loads the view to either side of the visible one. This provides the smooth scrolling from view to view that makes the ViewPager so cool.
To achieve the effect you want, you need to do a couple of things.
Change the FragmentPagerAdapter to a FragmentStatePagerAdapter. The reason for this is that the FragmentPagerAdapter will keep all the views that it loads into memory forever. Where the FragmentStatePagerAdapter disposes of views that fall outside the current and traversable views.
Override the adapter method getItemPosition (shown below). When we callmAdapter.notifyDataSetChanged(); the ViewPager interrogates the adapter to determine what has changed in terms of positioning. We use this method to say that everything has changed so reprocess all your view positioning。
大致意思如下:
Viewpgaer不会删除Fragment是因为它会加载多个View或者Fragment到内存,对于可见的View,它还会加载左右的View,这样才能保证滑动流畅。
一.首先需要继承FragmentStatePagerAdapter,因为FragmentPagerAdapter会永久保存所有加载的View到内存,这时你做任何删除操作都是无用的,但是FragmentStatePagerAdapter不会。
二.当我们用Viewpager的Adapter.notifyDataSetChanged()的时候,Viewpgaer会去查询到底哪个位置有改变,当我们视线了getItemPosition的如上方法,就是告诉所有的View都已经变化,从而达到刷新的目的。