您的位置:首页 > 移动开发 > Android开发

fragment更新数据后使用notifyDataSetChanged()无效

2016-10-18 16:39 246 查看
页面是根据网络数据返回的list数据动态生成的几个fragment构成的

修改包含fragment的集合数据

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_UNCHANGEDiftheposition
ofthegivenitemhasnotchangedorPOSITION_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 viewpager fragment