Android 中ViewPager重排序与更新实例详解
Android中ViewPager重排序与更新实例详解
最近的项目中有栏目订阅功能,在更改栏目顺序以后需要更新ViewPager。类似于网易新闻的频道管理。
在重新排序之后调用了PagerAdapter的notifyDataSetChanged方法,发现ViewPager并没有更新,于是我开始跟踪源码,在调用PagerAdapter的notifyDataSetChanged方法后,会触发Viewpager的dataSetChanged方法。
voiddataSetChanged(){
//Thismethodonlygetscalledifourobserverisattached,somAdapterisnon-null.
finalintadapterCount=mAdapter.getCount();
mExpectedAdapterCount=adapterCount;
booleanneedPopulate=mItems.size()
通过源码发现,在发生数据更新是,ViewPager会调用Adapter.getItemPosition判断当前页是否发生变化,如果当前页没有变化则返回POSITION_UNCHANGED,如果当前页的顺序发生变化则返回新的索引,如果当前页不存在则返回POSITION_NONE将会移除当前页并更新当前页。
接着查看ViewPagerAdapter的getItemPosition方法
publicintgetItemPosition(Objectobject){
returnPOSITION_UNCHANGED;
}
发现默认返回POSITION_UNCHANGED,这也是为什么我们的ViewPager没有更新的原因,网上有多种解决方案,其中一种是直接重写getItemPosition直接返回POSITION_NONE。我也试着使用了,发现并没有什么用,数据还是没有更新,后来发现我的Adapter继承的是FragmentPagerAdapter。而FragmentPagerAdapter自带了缓存策略,查看其instantiateItem方法。
@Override
publicObjectinstantiateItem(ViewGroupcontainer,intposition){
if(mCurTransaction==null){
mCurTransaction=mFragmentManager.beginTransaction();
}
finallongitemId=getItemId(position);
//Dowealreadyhavethisfragment?
Stringname=makeFragmentName(container.getId(),itemId);
Fragmentfragment=mFragmentManager.findFragmentByTag(name);
if(fragment!=null){
if(DEBUG)Log.v(TAG,"Attachingitem#"+itemId+":f="+fragment);
mCurTransaction.attach(fragment);
}else{
fragment=getItem(position);
if(DEBUG)Log.v(TAG,"Addingitem#"+itemId+":f="+fragment);
mCurTransaction.add(container.getId(),fragment,
makeFragmentName(container.getId(),itemId));
}
if(fragment!=mCurrentPrimaryItem){
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
returnfragment;
}
我们可以发现FragmentPagerAdapter通过其内部的FragmentManager管理Fragment缓存,而每一个Fragment都是通过name来分别的,而name则由makeFragmentName生成,我们查看makeFragmentName方法
privatestaticStringmakeFragmentName(intviewId,longid){
return"android:switcher:"+viewId+":"+id;
}
很简单拼接的字符串,一个是Viewpager的id,一个是由getItemId方法生成,而getItemId方法更简单直接返回position,这也就是为什么我们不能更新数据的原因。
/**
*Returnauniqueidentifierfortheitematthegivenposition.
*
*Thedefaultimplementationreturnsthegivenposition.
*Subclassesshouldoverridethismethodifthepositionsofitemscanchange.
*
*@parampositionPositionwithinthisadapter
*@returnUniqueidentifierfortheitematposition
*/
publiclonggetItemId(intposition){
returnposition;
}
知道原因以后接着就开始改造Adapter,首先为每一个频道生成唯一的ID我的做法是使用一个Map来保存,频道名称与ID的对应关系,使用一个List来保存之前的Position顺序,记得在notifyDataSetChanged中初始化,由于List保存的是之前的Position所以需要在完成更新后,再添加。
intid=1;
MapIdsMap=newHashMap<>();
ListpreIds=newArrayList<>();
@Override
publicvoidnotifyDataSetChanged(){
for(MenuInfoinfo:data){
if(!IdsMap.containsKey(info.getTitle())){
IdsMap.put(info.getTitle(),id++);
}
}
super.notifyDataSetChanged();
preIds.clear();
intsize=getCount();
for(inti=0;i
接着重写getItemPosition
@Override
publicintgetItemPosition(Objectobject){
ItemFragmentfragment=(ItemFragment)object;
Stringtitle=fragment.getTitle();
intpreId=preIds.indexOf(fragment.getTitle());
intnewId=-1;
inti=0;
intsize=getCount();
for(;i
还有getItemId
@Override
publiclonggetItemId(intposition){
returnIdsMap.get(getPageTitle(position));
}
完整的代码
packagecom.trs.xizang.gov.adapter;
importandroid.os.Bundle;
importandroid.support.v4.app.Fragment;
importandroid.support.v4.app.FragmentManager;
importandroid.support.v4.app.FragmentPagerAdapter;
importandroid.util.Log;
importandroid.view.ViewGroup;
importcom.trs.lib.base.TRSUrlFragment;
importcom.trs.lib.bean.TRSMenu;
importcom.trs.lib.fragment.base.SimpleTitleFragment;
importcom.trs.xizang.gov.bean.MenuInfo;
importcom.trs.xizang.gov.fragment.ItemFragment;
importjava.util.ArrayList;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;
/**
*Createdbyzhuguohuion2016/5/12.
*/
publicclassMenuInfoPageAdapterextendsFragmentPagerAdapter{
Listdata;
intid=1;
MapIdsMap=newHashMap<>();
ListpreIds=newArrayList<>();
publicMenuInfoPageAdapter(FragmentManagermanager,Listdata){
super(manager);
this.data=data==null?newArrayList():data;
}
@Override
publicintgetCount(){
returndata.size();
}
@Override
publicFragmentgetItem(intposition){
ItemFragmentfragment=newItemFragment();
Bundlebundle=newBundle();
bundle.putString(TRSUrlFragment.KEY_URL,data.get(position).getUrl());
bundle.putString(TRSUrlFragment.KEY_TITLE,data.get(position).getTitle());
fragment.setArguments(bundle);
returnfragment;
}
@Override
publicCharSequencegetPageTitle(intposition){
returndata.get(position).getTitle();
}
@Override
publicObjectinstantiateItem(ViewGroupcontainer,intposition){
returnsuper.instantiateItem(container,position);
}
@Override
publiclonggetItemId(intposition){
returnIdsMap.get(getPageTitle(position));
}
@Override
publicintgetItemPosition(Objectobject){
ItemFragmentfragment=(ItemFragment)object;
Stringtitle=fragment.getTitle();
intpreId=preIds.indexOf(fragment.getTitle());
intnewId=-1;
inti=0;
intsize=getCount();
for(;i
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!