国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android 中ViewPager重排序與更新實例詳解

2019-12-12 02:32:47
字體:
來源:轉載
供稿:網友

Android 中ViewPager重排序與更新實例詳解

最近的項目中有欄目訂閱功能,在更改欄目順序以后需要更新ViewPager。類似于網易新聞的頻道管理。

在重新排序之后調用了PagerAdapter的notifyDataSetChanged方法,發現ViewPager并沒有更新,于是我開始跟蹤源碼,在調用PagerAdapter的notifyDataSetChanged方法后,會觸發Viewpager的dataSetChanged方法。

 void dataSetChanged() {    // This method only gets called if our observer is attached, so mAdapter is non-null.    final int adapterCount = mAdapter.getCount();    mExpectedAdapterCount = adapterCount;    boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 &&        mItems.size() < adapterCount;    int newCurrItem = mCurItem;    boolean isUpdating = false;    for (int i = 0; i < mItems.size(); i++) {      final ItemInfo ii = mItems.get(i);      final int newPos = 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) {          // Keep the current item in the valid range          newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1));          needPopulate = true;        }        continue;      }      if (ii.position != newPos) {        if (ii.position == mCurItem) {          // Our current item changed position. Follow it.          newCurrItem = newPos;        }        ii.position = newPos;        needPopulate = true;      }    }    if (isUpdating) {      mAdapter.finishUpdate(this);    }    Collections.sort(mItems, COMPARATOR);    if (needPopulate) {      // Reset our known page widths; populate will recompute them.      final int childCount = getChildCount();      for (int i = 0; i < childCount; i++) {        final View child = getChildAt(i);        final LayoutParams lp = (LayoutParams) child.getLayoutParams();        if (!lp.isDecor) {          lp.widthFactor = 0.f;        }      }      setCurrentItemInternal(newCurrItem, false, true);      requestLayout();    }  }

通過源碼發現,在發生數據更新是,ViewPager會調用Adapter.getItemPosition判斷當前頁是否發生變化,如果當前頁沒有變化則返回POSITION_UNCHANGED,如果當前頁的順序發生變化則返回新的索引,如果當前頁不存在則返回POSITION_NONE將會移除當前頁并更新當前頁。

接著查看ViewPagerAdapter的getItemPosition方法

 public int getItemPosition(Object object) {    return POSITION_UNCHANGED;  }

發現默認返回POSITION_UNCHANGED,這也是為什么我們的ViewPager沒有更新的原因,網上有多種解決方案,其中一種是直接重寫getItemPosition直接返回POSITION_NONE。我也試著使用了,發現并沒有什么用,數據還是沒有更新,后來發現我的Adapter繼承的是FragmentPagerAdapter。而FragmentPagerAdapter自帶了緩存策略,查看其instantiateItem方法。

 @Override  public Object instantiateItem(ViewGroup container, int position) {    if (mCurTransaction == null) {      mCurTransaction = mFragmentManager.beginTransaction();    }    final long itemId = getItemId(position);    // Do we already have this fragment?    String name = makeFragmentName(container.getId(), itemId);    Fragment fragment = mFragmentManager.findFragmentByTag(name);    if (fragment != null) {      if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);      mCurTransaction.attach(fragment);    } else {      fragment = getItem(position);      if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);      mCurTransaction.add(container.getId(), fragment,          makeFragmentName(container.getId(), itemId));    }    if (fragment != mCurrentPrimaryItem) {      fragment.setMenuVisibility(false);      fragment.setUserVisibleHint(false);    }    return fragment;  }

我們可以發現FragmentPagerAdapter通過其內部的FragmentManager管理Fragment緩存,而每一個Fragment都是通過name來分別的,而name則由makeFragmentName生成,我們查看makeFragmentName方法

 private static String makeFragmentName(int viewId, long id) {    return "android:switcher:" + viewId + ":" + id;  }

很簡單拼接的字符串,一個是Viewpager的id,一個是由getItemId方法生成,而getItemId方法更簡單直接返回position,這也就是為什么我們不能更新數據的原因。

  /**   * Return a unique identifier for the item at the given position.   *   * <p>The default implementation returns the given position.   * Subclasses should override this method if the positions of items can change.</p>   *   * @param position Position within this adapter   * @return Unique identifier for the item at position   */  public long getItemId(int position) {    return position;  }

知道原因以后接著就開始改造Adapter,首先為每一個頻道生成唯一的ID我的做法是使用一個Map來保存,頻道名稱與ID的對應關系,使用一個List來保存之前的Position順序,記得在notifyDataSetChanged中初始化,由于List保存的是之前的Position所以需要在完成更新后,再添加。

int id=1;  Map<String,Integer> IdsMap=new HashMap<>();  List<String> preIds=new ArrayList<>(); @Override  public void notifyDataSetChanged() {    for(MenuInfo info:data){      if(!IdsMap.containsKey(info.getTitle())){        IdsMap.put(info.getTitle(),id++);      }    }    super.notifyDataSetChanged();    preIds.clear();    int size=getCount();    for(int i=0;i<size;i++){      preIds.add((String) getPageTitle(i));    }  }

接著重寫getItemPosition

 @Override  public int getItemPosition(Object object) {    ItemFragment fragment= (ItemFragment) object;    String title=fragment.getTitle();    int preId = preIds.indexOf(fragment.getTitle());    int newId=-1;    int i=0;    int size=getCount();    for(;i<size;i++){      if(getPageTitle(i).equals(fragment.getTitle())){        newId=i;        break;      }    }    if(newId!=-1&&newId==preId){      Log.i("zgh","title="+title+" POSITION_UNCHANGED");      return POSITION_UNCHANGED;    }    if(newId!=-1){      Log.i("zgh","title="+title+" newId="+newId);      return newId;    }    Log.i("zgh","title="+title+" POSITION_NONE");    return POSITION_NONE;  }

還有getItemId

 @Override  public long getItemId(int position) {    return IdsMap.get(getPageTitle(position));  }

完整的代碼

package com.trs.xizang.gov.adapter;import android.os.Bundle;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;import android.support.v4.app.FragmentPagerAdapter;import android.util.Log;import android.view.ViewGroup;import com.trs.lib.base.TRSUrlFragment;import com.trs.lib.bean.TRSMenu;import com.trs.lib.fragment.base.SimpleTitleFragment;import com.trs.xizang.gov.bean.MenuInfo;import com.trs.xizang.gov.fragment.ItemFragment;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/** * Created by zhuguohui on 2016/5/12. */public class MenuInfoPageAdapter extends FragmentPagerAdapter {  List<MenuInfo> data;  int id=1;  Map<String,Integer> IdsMap=new HashMap<>();  List<String> preIds=new ArrayList<>();  public MenuInfoPageAdapter(FragmentManager manager, List<MenuInfo> data){    super(manager);    this.data= data==null? new ArrayList<MenuInfo>() :data;  }  @Override  public int getCount() {    return data.size();  }  @Override  public Fragment getItem(int position) {    ItemFragment fragment=new ItemFragment();    Bundle bundle=new Bundle();    bundle.putString(TRSUrlFragment.KEY_URL,data.get(position).getUrl());    bundle.putString(TRSUrlFragment.KEY_TITLE, data.get(position).getTitle());    fragment.setArguments(bundle);    return fragment;  }  @Override  public CharSequence getPageTitle(int position) {    return data.get(position).getTitle();  }  @Override  public Object instantiateItem(ViewGroup container, int position) {    return super.instantiateItem(container, position);  }  @Override  public long getItemId(int position) {    return IdsMap.get(getPageTitle(position));  }  @Override  public int getItemPosition(Object object) {    ItemFragment fragment= (ItemFragment) object;    String title=fragment.getTitle();    int preId = preIds.indexOf(fragment.getTitle());    int newId=-1;    int i=0;    int size=getCount();    for(;i<size;i++){      if(getPageTitle(i).equals(fragment.getTitle())){        newId=i;        break;      }    }    if(newId!=-1&&newId==preId){      Log.i("zgh","title="+title+" POSITION_UNCHANGED");      return POSITION_UNCHANGED;    }    if(newId!=-1){      Log.i("zgh","title="+title+" newId="+newId);      return newId;    }    Log.i("zgh","title="+title+" POSITION_NONE");    return POSITION_NONE;  }  @Override  public void notifyDataSetChanged() {    for(MenuInfo info:data){      if(!IdsMap.containsKey(info.getTitle())){        IdsMap.put(info.getTitle(),id++);      }    }    super.notifyDataSetChanged();    preIds.clear();    int size=getCount();    for(int i=0;i<size;i++){      preIds.add((String) getPageTitle(i));    }  }}

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 扬中市| 桦甸市| 泸西县| 潢川县| 麟游县| 甘孜县| 班玛县| 阿拉善左旗| 静安区| 博爱县| 南乐县| 甘洛县| 长葛市| 麻城市| 昭通市| 阳春市| 临湘市| 珠海市| 深水埗区| 横山县| 佳木斯市| 甘谷县| 油尖旺区| 达尔| 昌江| 曲麻莱县| 曲水县| 渭南市| 雷州市| 长汀县| 白城市| 阜城县| 玉溪市| 孝感市| 延长县| 班戈县| 上饶县| 鸡西市| 宣武区| 弥勒县| 余江县|