问题描述
ViewPager的刷新机制和ListView不太一样,ListView中当调用Adapter的notifyDataSetChanged方法后会把列表所有itemView重新绘制一遍。ViewPager在初始化后会生成一些itemView(这个可以通过setOffscreenPageLimit方法设置),ViewPager相当于缓存了几个view,当调用notifyDataSetChanged方法后这几个view是不会重绘的,这就导致数据应该已经更新了,但是左右滑动发现itemView显示的还是之前的数据,滑到后面再滑回来又好了。
解决方法
PagerAdapter有个方法
@Override
public int getItemPosition(Object object) {
return super.getItemPosition(object);
}
当调用notifyDataSetChanged方法时会调用它,当它返回POSITION_NONE的时候就会重绘这个itemView。这里的object是instantiateItem方法的返回值,一般都是itemView。
之前用的比较简单粗暴的方法,直接返回POSITION_NONE,不管什么都重绘。直到我学会了利用View的tag。
在调用notifyDataSetChanged的时候才需要刷新缓存的view,那我们可以重写notifyDataSetChanged方法
@Override
public void notifyDataSetChanged() {
for (int i = 0; i < viewPager.getChildCount(); i++) {
View child = viewPager.getChildAt(i);
child.setTag(R.id.isneedrefresh_tag, true);
}
super.notifyDataSetChanged();
}
给ViewPager的已缓存item加上tag标志是否需要刷新,我这里直接通过viewPager.getChildAt方法获取了,这个自己用列表管理更好。
然后重写getItemPosition方法,获取view的tag,如果是需要刷新的就返回POSITION_NONE,这样就不会影响ViewPager原有的逻辑。
@Override
public int getItemPosition(Object object) {
if ((boolean) ((View) object).getTag(R.id.isneedrefresh_tag)) {
return POSITION_NONE;
}
return super.getItemPosition(object);
}
每当生成新的itemView的时候,给view设置标志
@Override
public Object instantiateItem(ViewGroup container, int position) {
View convertView;
ViewHolder holder;
if (viewRecycler.size() > 0) {
convertView = viewRecycler.poll();
holder = (ViewHolder) convertView.getTag(R.id.viewholder_tag);
} else {
convertView = inflater.inflate(R.layout.item, container, false);
holder = new ViewHolder();
convertView.setTag(R.id.viewholder_tag, holder);
}
convertView.setTag(R.id.isneedrefresh_tag, false);
container.addView(convertView);
return convertView;
}
注:这里ViewHolder是仿照listView的复用View的思想,利用一个队列保存本应被销毁的View
Queue<View> viewRecycler;
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
View view = (View) object;
container.removeView(view);
viewRecycler.add(view);
}