android viewPager的notifyDataSetChanged()的方法无法刷新页面的分析
2015-09-22 22:32
387 查看
很久不写blog了,今天遇到问题了记录一下别人的解决方法。
相信很多做过Viewpager的同学肯定遇到过这个问题,这个是bug还是android就是如此设计的,我们不做讨论。总之,它确实影响我们功能的实现了。
可能不少同学选择为Viewpager重新设置一遍适配器adapter,达到刷新的目的。但是这种方法在大多数情况下,是有问题的。
为什么调用数据更新的方法,Viewpager却没有更新呢,我们跟进该方法的源代码看一下。
首先查看适配器调用的super.notifyDataSetChanged(),该方法调到抽象基类PagerAdapter.notifyDataSetChanged()中:
注释里说到,当附加在适配器上的数据发生变化时,应该调用该方法刷新数据。该方法调用了一个mObservable.notifyChanged();
我们继续跟进这个方法,进入DataSetObservable类中,发现这样一段代码:
这都不是重点,重点我们来看这个mObservers的类型是一个抽象类DataSetObserver,里面只有两个未实现的方法,都有谁使用了这个抽象类呢,快捷键ctrl+alt+H,在众多的调用者当中,我们发现了Viewpager的身影
进入viewpager,我们终于找到了viewpager中控制数据变更的重点方法dataSetChanged,这个方法如下:
重点看这样一行代码:
官方对getItemPosition()的解释是:
Calledwhenthehostviewisattemptingtodetermineifanitem’spositionhaschanged.ReturnsPOSITION_UNCHANGEDif
thepositionofthegivenitemhasnotchangedorPOSITION_NONEiftheitemisnolongerpresentintheadapter.
ThedefaultimplementationassumesthatitemswillneverchangepositionandalwaysreturnsPOSITION_UNCHANGED.
意思是如果item的位置如果没有发生变化,则返回POSITION_UNCHANGED。如果返回了POSITION_NONE,表示该位置的item已经不存在了。默认的实现是假设item的位置永远不会发生变化,而返回POSITION_UNCHANGED
所以我们可以尝试着修改适配器的写法,覆盖getItemPosition()方法,当调用notifyDataSetChanged时,让getItemPosition方法人为的返回POSITION_NONE,从而达到强迫viewpager重绘所有item的目的。
具体代码如下:
Viewpager在调用notifyDataSetChanged()时,界面无刷新。
相信很多做过Viewpager的同学肯定遇到过这个问题,这个是bug还是android就是如此设计的,我们不做讨论。总之,它确实影响我们功能的实现了。可能不少同学选择为Viewpager重新设置一遍适配器adapter,达到刷新的目的。但是这种方法在大多数情况下,是有问题的。
追踪源代码:
为什么调用数据更新的方法,Viewpager却没有更新呢,我们跟进该方法的源代码看一下。首先查看适配器调用的super.notifyDataSetChanged(),该方法调到抽象基类PagerAdapter.notifyDataSetChanged()中:
/**
*Thismethodshouldbecalledbytheapplicationifthedatabackingthisadapterhaschanged
*andassociatedviewsshouldupdate.
*/
publicvoidnotifyDataSetChanged(){
mObservable.notifyChanged();
}
注释里说到,当附加在适配器上的数据发生变化时,应该调用该方法刷新数据。该方法调用了一个mObservable.notifyChanged();
我们继续跟进这个方法,进入DataSetObservable类中,发现这样一段代码:
/**
*Invokes{@linkDataSetObserver#onChanged}oneachobserver.
*Calledwhenthecontentsofthedatasethavechanged.Therecipient
*willobtainthenewcontentsthenexttimeitqueriesthedataset.
*/
publicvoidnotifyChanged(){
synchronized(mObservers){
//sinceonChanged()isimplementedbytheapp,itcoulddoanything,including
//removingitselffrom{@linkmObservers}-andthatcouldcauseproblemsif
//aniteratorisusedontheArrayList{@linkmObservers}.
//toavoidsuchproblems,justmarchthruthelistinthereverseorder.
for(inti=mObservers.size()-1;i>=0;i--){
mObservers.get(i).onChanged();
}
}
}
这都不是重点,重点我们来看这个mObservers的类型是一个抽象类DataSetObserver,里面只有两个未实现的方法,都有谁使用了这个抽象类呢,快捷键ctrl+alt+H,在众多的调用者当中,我们发现了Viewpager的身影
进入viewpager,我们终于找到了viewpager中控制数据变更的重点方法dataSetChanged,这个方法如下:
voiddataSetChanged(){
//Thismethodonlygetscalledifourobserverisattached,somAdapterisnon-null.
booleanneedPopulate=mItems.size()<mOffscreenPageLimit*2+1&&
mItems.size()<mAdapter.getCount();
intnewCurrItem=mCurItem;
booleanisUpdating=false;
for(inti=0;i<mItems.size();i++){
finalItemInfoii=mItems.get(i);
finalintnewPos=mAdapter.getItemPosition(ii.object);
if(newPos==PagerAdapter.POSITION_UNCHANGED){
continue;
}
if(newPos==PagerAdapter.POSITION_NONE){
mItems.remove(i);
i--;
if(!isUpdating){
mAdapter.startUpdate(this);
isUpdating=true;
}
mAdapter.destroyItem(this,ii.position,ii.object);
needPopulate=true;
if(mCurItem==ii.position){
//Keepthecurrentiteminthevalidrange
newCurrItem=Math.max(0,Math.min(mCurItem,mAdapter.getCount()-1));
needPopulate=true;
}
continue;
}
if(ii.position!=newPos){
if(ii.position==mCurItem){
//Ourcurrentitemchangedposition.Followit.
newCurrItem=newPos;
}
ii.position=newPos;
needPopulate=true;
}
}
if(isUpdating){
mAdapter.finishUpdate(this);
}
Collections.sort(mItems,COMPARATOR);
if(needPopulate){
//Resetourknownpagewidths;populatewillrecomputethem.
finalintchildCount=getChildCount();
for(inti=0;i<childCount;i++){
finalViewchild=getChildAt(i);
finalLayoutParamslp=(LayoutParams)child.getLayoutParams();
if(!lp.isDecor){
lp.widthFactor=0.f;
}
}
setCurrentItemInternal(newCurrItem,false,true);
requestLayout();
}
}
重点看这样一行代码:
finalintnewPos=mAdapter.getItemPosition(ii.object);
if(newPos==PagerAdapter.POSITION_UNCHANGED){
continue;
}
官方对getItemPosition()的解释是:
Calledwhenthehostviewisattemptingtodetermineifanitem’spositionhaschanged.ReturnsPOSITION_UNCHANGEDif
thepositionofthegivenitemhasnotchangedorPOSITION_NONEiftheitemisnolongerpresentintheadapter.
ThedefaultimplementationassumesthatitemswillneverchangepositionandalwaysreturnsPOSITION_UNCHANGED.
意思是如果item的位置如果没有发生变化,则返回POSITION_UNCHANGED。如果返回了POSITION_NONE,表示该位置的item已经不存在了。默认的实现是假设item的位置永远不会发生变化,而返回POSITION_UNCHANGED
解决方案:
所以我们可以尝试着修改适配器的写法,覆盖getItemPosition()方法,当调用notifyDataSetChanged时,让getItemPosition方法人为的返回POSITION_NONE,从而达到强迫viewpager重绘所有item的目的。具体代码如下:
classSearchAdapterextendsPagerAdapter{
privateintmChildCount=0;
@Override
publicvoidnotifyDataSetChanged(){
mChildCount=getCount();
super.notifyDataSetChanged();
}
@Override
publicintgetItemPosition(Objectobject){
if(mChildCount>0){
mChildCount--;
returnPOSITION_NONE;
}
returnsuper.getItemPosition(object);
}
}
相关文章推荐
- android系统触摸屏虚拟按键
- Android进程间通信(IPC)机制Binder简要介绍和学习计划
- Android调试的各种bug
- Android 位置服务——BaiduMap的使用
- Android_开发人员经常使用的颜色
- Android:关于声明文件中android:process属性说明
- Android中handler和receiver等用于传递消息时的区别
- Android环境搭建要点
- Android中Thread和Service的区别(两篇不错的讲解)
- Android Studio 插件--postfix
- Android基于位置的服务开发,百度地图的使用
- android 事件总线 -- Otto(二) Produce、Subscribe
- (4.1.23.2)Android 属性动画(Property Animation) 完全解析 (下)
- (4.1.23.1)Android 属性动画(Property Animation) 完全解析 (上)
- Android M -- Power-Saving Optimizations
- Android——采用SQLiteDatabase操作SQLite数据库
- Android内存泄露
- [转]Android中常用适配器及定义自己的适配器
- [转]Android适配器之ArrayAdapter、SimpleAdapter和BaseAdapter的简单用法与有用代码片段
- android图像缓存问题