700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > android 排序view Android 中ViewPager重排序与更新实例详解

android 排序view Android 中ViewPager重排序与更新实例详解

时间:2024-05-07 07:47:42

相关推荐

android 排序view Android 中ViewPager重排序与更新实例详解

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.

*

*

The default implementation returns the given position.

* Subclasses should override this method if the positions of items can change.

*

* @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 IdsMap=new HashMap<>();

List 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

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

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 /5/12.

*/

public class MenuInfoPageAdapter extends FragmentPagerAdapter {

List data;

int id=1;

Map IdsMap=new HashMap<>();

List preIds=new ArrayList<>();

public MenuInfoPageAdapter(FragmentManager manager, List data){

super(manager);

this.data= data==null? new ArrayList() :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

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

preIds.add((String) getPageTitle(i));

}

}

}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。