ViewPager刷新问题详解

作者:李旺成

时间:2016年5月3日


一、PagerAdapter介绍

先行押作用图

PageAdapter 使用示例

PagerAdapter简介

ListView 大家应该还特别熟稔吧!ListView 一般还需一个 Adapter
来填充数据,如 ArrayAdapter、SimpleAdapter。PagerAdapter 就是 ViewPager
的 Adapter,与 ListView 的 Adapter 作用一样。

ViewPager->PageAdapter == ListView->BaseAdapter

先看下合法介绍

法定介绍

PageAdapter 类

PageAdapter 继承自
Object,继承结构参考意义不很,那老实看文档。文档上无提供示范代码,只是说了产要于定义
PageAdapter 需要贯彻下面四独法子:

  • instantiateItem(ViewGroup container, int
    position):
    欠方法的功能是创建指定位置的页面视图。适配器有责任增加将创建的
    View 视图到此处给定的 container 中,这是以确保于
    finishUpdate(viewGroup) 返回时 this is be done!
    返回值:返回一个意味新增视图页面的
    Object(Key),这里没有必要非要是回来视图本身,也足以是页面的旁容器。其实自己的亮是足以象征时页面的任意值,只要你得跟你增加的
    View 一一对应即可,比如 position 变量也得开为 Key
  • destroyItem(ViewGroup container, int position, Object
    object):
    拖欠方式的功用是移除一个加以位置的页面。适配器有义务从容器中去除这个视图,这是为保险以
    finishUpdate(viewGroup) 返回时视图能够被移除
  • getCount():返回时行视图的多寡
  • isViewFromObject(View view, Object object):拖欠函数用来判断
    instantiateItem() 函数所返回来的 Key
    与一个页面视图是否是意味的以及一个视图(即她俩是否是应和的,对应之代表和一个
    View)
    返回值:如果对应之凡和一个View,返回 true,否则回 false

点对 PageAdapter 的季独抽象方法做了大概说明,下面看看哪利用

简单以

mContentVP.setAdapter(new PagerAdapter() {
    @Override
    public int getCount() {
        return dataList.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View view = View.inflate(SimpleDemoActivity.this, R.layout.item_vp_demopageradapter, null);
        TextView pageNumTV = (TextView) view.findViewById(R.id.tv_pagenum);
        pageNumTV.setText("DIY-PageNum-" + dataList.get(position));
        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

});

得看来实现 PagerAdapter 与 BaseAdapter 很相近,只是 PagerAdapter 的
isViewFromObject() 与 instantiateItem() 方法需要优秀掌握下。这里以简化
PagerAdapter 的使用,我做了单简单的包裹:

public abstract class APagerAdapter<T> extends PagerAdapter {

    protected LayoutInflater mInflater;
    protected List<T> mDataList;
    private SparseArray<View> mViewSparseArray;

    public APagerAdapter(Context context, List<T> dataList) {
        mInflater = LayoutInflater.from(context);
        mDataList = dataList;
        mViewSparseArray = new SparseArray<View>(dataList.size());
    }

    @Override
    public int getCount() {
        if (mDataList == null) return 0;
        return mDataList.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View view = mViewSparseArray.get(position);
        if (view == null) {
            view = getView(position);
            mViewSparseArray.put(position, view);
        }
        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView(mViewSparseArray.get(position));
    }

    public abstract View getView(int position);

}

APagerAdapter 类模仿 ListView 的 BaseAdapter,抽象出一个 getView()
方法,在中间用 SparesArray 缓存所有显示过之
View。这样使就可怜简单了,继承 APagerAdapter,实现 getView()
方法即可(可以参照:DemoPagerAdapter.java)。

PagerAdapter 刷新的题材

提出问题

每当运 ListView 的时光,我们反复习惯了翻新 Adapter 的数据源,然后调用
Adapter 的 notifyDataSetChanged() 方法来刷新列表(有无小 MVC
的感觉)。

PagerAdapter 也生 notifyDataSetChanged()
方法,那我们按这个流程来试试,看有无产生什么问题。(ListView
的言传身教就未以此处演示了,感兴趣的好团结去试试,非常简单)

那么自己的题目是:“ViewPager 的 PagerAdapter
在数据源更新后,能否自行刷新视图?

拉动在题材,我们召开有试行,下面实验的思路是:修改数据源,然后通知
PagerAdapter 更新,查看视图的别。

试验环境准备

省实验环境,上代码:

private void initData() {
    // 数据源
    mDataList = new ArrayList<>(5);
    mDataList.add("Java");
    mDataList.add("Android");
    mDataList.add("C&C++");
    mDataList.add("OC");
    mDataList.add("Swift");

    // 很简单的一个 PagerAdapter
    this.mContentVP.setAdapter(mPagerAdapter = new PagerAdapter() {
        @Override
        public int getCount() {
            return mDataList.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            View view = View.inflate(SimpleDemoActivity.this, R.layout.item_vp_demopageradapter, null);
            TextView pageNumTV = (TextView) view.findViewById(R.id.tv_pagenum);
            pageNumTV.setText("DIY-PageNum-" + mDataList.get(position));
            container.addView(view);
            return view;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }

    });
}

ViewPager 的 Item:item_vp_demopageradapter.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center">
    <ImageView
        android:id="@+id/iv_img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/activity_horizontal_margin"
        android:src="@mipmap/ic_launcher" />
    <!-- 用于显示文本,数据更新体现在这里 -->
    <TextView
        android:id="@+id/tv_pagenum"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/activity_horizontal_margin"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="DIY-Page-" />
</LinearLayout>

颇粗略的代码,并且加了诠释,直接向生看实验。

PagerAdapter 刷新实验

1、更新数据源中的某项

更新数据测试

对诺代码:

private void refresh() {
    mDataList.set(0, "更新数据源测试");
    mPagerAdapter.notifyDataSetChanged();
}

题材讲述:以示范动画中可以看,更新数据源之后视图并无应声刷新,多滑行几坏再返回更新的
Item 时才履新(这里先看题目,下面会细说)。

2、往数据源中添加数据

加上数据测试

对承诺代码:

private void add() {
    mDataList.add("这是新添加的Item");
    mPagerAdapter.notifyDataSetChanged();
}

题材讲述:举重若轻问题,数据源添加数据后通报 PagerAdapter
刷新,ViewPager 中便基本上矣一个 Item。

3、从数源中删除数据

删除数据测试

private void delete() {
    mDataList.remove(0);
    mPagerAdapter.notifyDataSetChanged();
}

题材讲述:本条问题就于多了,首先,假若是去除时
Item,那么会盼莫外反响;其次,若是除去的匪是当下
Item,会意识并发了数量错乱,并且后面有 Item
滑不过去,但是本停往后滑的时光可以看到后的 Item。

4、将数据源清空

清空数据

private void clean() {
    mDataList.clear();
    mPagerAdapter.notifyDataSetChanged();
}

题目讲述:打点的动图可以看出,清空数据源之后,会留一个 Item。

说明:优先不用争上面所形容的 PagerAdapter
是否来题目,这里只是想引出问题来,下面会指向
PagerAdapter、FragmentPagerAdapter 以及 FragmentStatePagerAdapter
来分析问题因与让出解决方案。

二、PagerAdapter

由者的试验可以视 ViewPager 不同于 ListView,如果就的调用
ViewPager.getAdapter().notifyDataSetChanged() 方法(即 PagerAdapter 的
notifyDataSetChanged()方法)页面并不曾刷新。

PagerAdapter 用于 ViewPager 的 Item 为一般
View的气象,这个相对简便易行,所以首先介绍。

深信不疑广大同室都抄了类似之题目 —— “PagerAdapter 的 notifyDataSetChanged()
不刷新?”。有的说马上是 bug,有的则认为 Google
是专门这样设计的,个人倾向后同种植意见(我以为就是 Google 为了 ViewPager
性能考虑要设计之,毕竟 ViewPager
需要出示“很多的”视图,而且要备用户滑动时当卡顿)。

ViewPager 刷新分析

事先来打听下 ViewPager 的基础代谢过程:
1、刷新的前奏
ViewPager 的基础代谢是打调用其 PagerAdapter 的 notifyDataSetChanged()
方法开始的,那先看看该办法的源码(在源码面前满无所遁形…):

/**
 * This method should be called by the application if the data backing this adapter has changed
 * and associated views should update.
 */
public void notifyDataSetChanged() {
    synchronized (this) {
        if (mViewPagerObserver != null) {
            mViewPagerObserver.onChanged();
        }
    }
    mObservable.notifyChanged();
}

2、DataSetObservable 的 notifyChanged()
上面的措施吃出现了少数独重点之成员变量:

private final DataSetObservable mObservable = new DataSetObservable();
private DataSetObserver mViewPagerObserver;

观察者模式,有无产生?先不急分析是是勿是观察者模式,来看望
mObservable.notifyChanged() 做了数什么工作:

/**
 * Invokes {@link DataSetObserver#onChanged} on each observer.
 * Called when the contents of the data set have changed.  The recipient
 * will obtain the new contents the next time it queries the data set.
 */
public void notifyChanged() {
    synchronized(mObservers) {
        // since onChanged() is implemented by the app, it could do anything, including
        // removing itself from {@link mObservers} - and that could cause problems if
        // an iterator is used on the ArrayList {@link mObservers}.
        // to avoid such problems, just march thru the list in the reverse order.
        for (int i = mObservers.size() - 1; i >= 0; i--) {
            mObservers.get(i).onChanged(); 
        }
    }
}

notifyChanged() 方法中凡雅典型的观察者模式遭遇遍历所有的 Observer,通知
变化来了的代码。代码很粗略,那要是是 mObservers 包含如何 Observer
呢?

3、DataSetObserver
直由 mObservers 点进去你见面发觉这:

protected final ArrayList<T> mObservers = new ArrayList<T>();

-_-‘,这是只泛型,坑了!还吓 DataSetObservable 的 notifyChanged()
的注解中形容了这些 Observer 是 DataSetObserver。那去探视 DataSetObserver:

public abstract class DataSetObserver {
    /**
     * This method is called when the entire data set has changed,
     * most likely through a call to {@link Cursor#requery()} on a {@link Cursor}.
     */
    public void onChanged() {
        // Do nothing
    }

    /**
     * This method is called when the entire data becomes invalid,
     * most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a
     * {@link Cursor}.
     */
    public void onInvalidated() {
        // Do nothing
    }
}

一个抽象类,里面少个缺损方法,这个好惩治,找他的子类(AndroidStudio 中
将光标放到类名上,按 F4):

DataSetObserver继承结构

好不容易找到你了,就是用红线框出来的那条,双击,定位过去。

4、PagerObserver 内部类
PagerObserver 是 ViewPager 中之一个间类,实现呢充分简单,就是调用了
ViewPager 中之 dataSetChanged() 方法,真正的根本来了。

private class PagerObserver extends DataSetObserver {
    @Override
    public void onChanged() {
        dataSetChanged();
    }
    @Override
    public void onInvalidated() {
        dataSetChanged();
    }
}

5、ViewPager 的 dataSetChanged()
这个法子的兑现比较丰富,里面的逻辑看上去分外复杂的,这里就是无显周底源码了,列下第一点:

...
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) {
        ...
        continue;
    }
    ...
}
...

面截取的代码中 for 循环之中有点儿只 continue
语句子,这或许是于重要的代码,幸好不用我们继承深入了,官方给起了说明:

Called when the host view is attempting to determine if an item’s
position has changed. Returns POSITION_UNCHANGED if the position of the
given item has not changed or POSITION_NONE if the item is no longer
present in the adapter.The default implementation assumes that items
will never change position and always returns POSITION_UNCHANGED.

大约的意思是:
比方 Item 的位置要没发生变化,则回 POSITION_UNCHANGED。如果回到了
POSITION_NONE,表示该职位的 Item 已经休在了。默认的落实是如果 Item
的职位永远不见面发生变化,而返
POSITION_UNCHANGED。(参考自:追根究底源码解决android疑难有关问题1-Viewpager之notifyDataSetChanged无刷新)

上面在源码里面跟了一大圈是不是尚是感到没有明朗,因为还有一个要命重点的类
—— PagerAdapter 没有介绍,再让点耐心,继续。

6、PagerAdapter 的行事流程
其实就是是 PagerAdapter 中法的施行各个,来探视
Leo8573
的剖析(个人感觉基本说成功了,所以一直拷过来了):

PagerAdapter 作为 ViewPager 的适配器,无论 ViewPager
有小页,PagerAdapter 在初始化时为就初始化开始之2独
View,即调用2次instantiateItem 道。而连下当 ViewPager
滑动时,PagerAdapter 都见面调用 destroyItem
方法以距离该页2独增幅以上之酷 View 销毁,以此保证 PagerAdapter
最多就管辖3个 View,且当前 View 是3只被之中等一个,如果手上 View
缺少两度的 View,那么就是 instantiateItem,如里发生超2只增幅的就是
destroyItem。

简单易行图示:

                 *
   ------+---+---+---+------
     ... 0 | 1 | 2 | 3 | 4 ...
   ------+---+---+---+------

现阶段 View 为2号 View,所以 PagerAdapter 管辖1、2、3老三个
View,接下去为左滑动–>

                 *
   ------+---+---+---+------
     ... 1 | 2 | 3 | 4 | 5 ...
   ------+---+---+---+------

滑动后,当前 View 变为3号 View,PagerAdapter 会 destroyItem
0号View,instantiateItem 5号 View,所以 PagerAdapter 管辖2、3、4三个
View。(参考自:有关ViewPager的数量更新问题总)

小结一下: Viewpager 的基础代谢过程是这般的,在历次调用 PagerAdapter 的
notifyDataSetChanged() 方法时,都见面激活 getItemPosition(Object object)
方法,该方法会遍历 ViewPager 的享有 Item(由缓存的 Item
数量控制,默认为当前页与那个左右加起并3页,这个可自动设定,但是起码会缓存2页),为每个
Item 返回一个状态值(POSITION_NONE/POSITION_UNCHANGED),如果是
POSITION_NONE,那么该 Item 会被 destroyItem(ViewGroup container, int
position, Object object) 方法 remove 掉,然后再加载,如果是
POSITION_UNCHANGED,就未会见再也加载,默认是
POSITION_UNCHANGED,所以要非还写 getItemPosition(Object
object),修改返回值,就无法看出 notifyDataSetChanged() 的刷新功能。

太简便的解决方案

那么就是直一刀切:重写 PagerAdapter 的 getItemPosition(Object object)
方法,将回值固定为 POSITION_NONE。

事先看看效果:

![极端简单易行解决方案示例](http://upload-images.jianshu.io/upload\_images/1233754-0071612440ec3200.gif?imageMogr2/auto-orient/strip
”最简便易行解决方案示例“)

上代码(PagerAdapterActivity.java):

@Override
public int getItemPosition(Object object) {
    // 最简单解决 notifyDataSetChanged() 页面不刷新问题的方法
    return POSITION_NONE;
}

欠方案的症结:发出只好强烈的老毛病,那即便是会见刷新有的
Item,这将导致系统资源的荒废,所以这种措施不切合数据量较充分之状况。

注意:
这种措施还有一个待留意的地方,就是重复写 destoryItem() 方法:

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    // 把 Object 强转为 View,然后将 view 从 ViewGroup 中清除
    container.removeView((View) object);
}

最简方案的优化

此提供一个思路,毕竟场景最多,相信大家知道了思路使贯彻即非常简短了,闲话不多说。

思路:在 instantiateItem() 方法被叫每个 View 添加 tag(使用 setTag()
方法),然后于 getItemPosition() 方法被通过 View.getTag()
来判断是否是索要刷新的页面,是不怕回到 POSITION_NONE,否就返回
POSITION_UNCHANGED。
(参考自:ViewPager刷新单个页面的艺术)

注意:此地发出几许只要留心的凡,当清空数据源的下要回到
POSITION_NONE,可用如下代码:

if (mDataList != null && mDataList.size()==0) {
    return POSITION_NONE;
}

有关 PagerAdapter 的牵线就顶此处了,虽然 FragmentPagerAdapter 与
FragmentStatePagerAdapter 都是继承自
PagerAdapter。但是,这简单只凡是专程为因 Fragment 为 Item 的 ViewPager
所准备的,所以有夫特殊性。且看下的牵线。

三、FragmentPagerAdapter

简介

面通过使 getItemPosition() 方法返回 POSITION_NONE
到达数据源变化(也就算是调用
notifyDataSetChanged())时,刷新视图的目的。但是当我们使用 Fragment 作为
ViewPager 的 Item 时,就需多着想部分了,而且一般是应用
FragmentPagerAdapter 或者 FragmentStatePagerAdapter。

这里不展开讨论 FragmentPagerAdapter 与 FragmentStatePagerAdapter
的异同以及运用状况了,感兴趣之可看看这首文章:FragmentPagerAdapter与FragmentStatePagerAdapter区别。

脚先来探望用 FragmentPagerAdapter 时,如何当数据源发生变化时,刷新
Fragment 或者动态改变 Items 的数。

方案:清除 FragmentManager 中缓存的 Fragment

预先看作用:

FragmentPagerAdapter数据源刷新演示1

心想事成上图效果的要代码:
1、FPagerAdapter1Activity.java

private void refresh() {
    if (checkData()) return;
    mDataList.set(0, 7); // 修改数据源
    mPagerAdapter.updateData(mDataList); // 通知 Adapter 更新
}

private void add() {
    mDataList.add(7);
    mPagerAdapter.updateData(mDataList);
}

private void delete() {
    if (checkData()) return;
    mDataList.remove(0);
    mPagerAdapter.updateData(mDataList);
}

private void clear() {
    if (checkData()) return;
    mDataList.clear();
    mPagerAdapter.updateData(mDataList);
}

2、FPagerAdapter1.java

public class FPagerAdapter1 extends FragmentPagerAdapter {

    private ArrayList<Fragment> mFragmentList;
    private FragmentManager mFragmentManager;

    public FPagerAdapter1(FragmentManager fm, List<Integer> types) {
        super(fm);
        this.mFragmentManager = fm;
        mFragmentList = new ArrayList<>();
        for (int i = 0, size = types.size(); i < size; i++) {
            mFragmentList.add(FragmentTest.instance(i));
        }
        setFragments(mFragmentList);
    }

    public void updateData(List<Integer> dataList) {
        ArrayList<Fragment> fragments = new ArrayList<>();
        for (int i = 0, size = dataList.size(); i < size; i++) {
            Log.e("FPagerAdapter1", dataList.get(i).toString());
            fragments.add(FragmentTest.instance(dataList.get(i)));
        }
        setFragments(fragments);
    }

    private void setFragments(ArrayList<Fragment> mFragmentList) {
        if(this.mFragmentList != null){
            FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
            for(Fragment f:this.mFragmentList){
                fragmentTransaction.remove(f);
            }
            fragmentTransaction.commit();
            mFragmentManager.executePendingTransactions();
        }
        this.mFragmentList = mFragmentList;
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return this.mFragmentList.size();
    }

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

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }
}

3、思路分析
面的代码思路好简短,就是当数据源发生变化时,先用 FragmentManger
里面有着缓存的 Fragment 全部免,然后重新创设,这样齐刷新视图的目的。

但是,这样做有一个弱点,那便是碰头造成不必要的荒废,会潜移默化性。还有即使是要采用一个
List 缓存所有的 Fragment,这为得占用多舅存…

思路特别简单,这里不再赘述,那看发生无发啊可优化的。

优化:通过 Tag 获取缓存的 Fragment

预先看成效:

FragmentPagerAdapter数据源刷新演示2

自打者的动图上得看看,更新某一个 Fragment
没有问题,清空数据源的时候吗不曾,添加本为从未什么问题;请留心去的效力,虽然,目的
Fragment 确实于 ViewPager
中易除,但是滑动后面的页面会发现并发了多少错乱。

浅析一下优化的思路

先来询问 FragmentPagerAdapter 中是怎么样管理 Fragment 的,这里提到到
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;
}

由源码中好看看于起 FragmentManager 中取出 Fragment 时调用了
findFragmentByTag() 方法,而以此 Tag 是由于 makeFragmentName()
方法生成的。继续朝生得见到各级一个 Fragment 都打及了一个签(在
mCurTransaction.add() 方法中)。

也就是说是 FragmentManager 通过 Tag 找相应的 Fragment,从而达到缓存
Fragment 的目的。如果得以找到,就不见面创造新的 Fragment,Fragment 的
onCreate()、onCreateView() 等办法还未会见再度调用。

优化的思绪就有了:
首先,用缓存所有 Fragment 的 Tag,代码如下:

private List<String> mTagList; // 用来存放所有的 Tag

// 生成 Tag
// 直接从 FragmentPageAdapter 源码里拷贝 Fragment 生成 Tag 的方法
private String makeFragmentName(int viewId, int index) {
    return "android:switcher:" + viewId + ":" + index;
}

// 将 Tag 缓存到 List 中
@Override
public Object instantiateItem(ViewGroup container, int position) {
    mTagList.add(position, makeFragmentName(container.getId(),
            (int) getItemId(position)));
    return super.instantiateItem(container, position);
}

其次,当更新 Fragment 时,使用相应的 Tag 去 FragmentManamager
中找找相应的 Fragment,如果是,就直接更新,代码如下:

public void update(int position, String str) {
    Fragment fragment = mFragmentManager.findFragmentByTag(mTagList.get(position));
    if (fragment == null) return;
    if (fragment instanceof FragmentTest) {
        ((FragmentTest)fragment).update(str);
    }
    notifyDataSetChanged();
}

拖欠措施需要活动在 Fragment 中提供。

最后,对动态改变 ViewPager 中 Fragment
的多寡,如果是加上,那不要紧要小心的;但是去有点棘手。

当点的动态及看,删除一个 Fragment
后会面世乱,这里没进一步失去研究了,这里仅仅提供一个演示供参考(这个示例代码有题目,仅供参考)

public void remove(int position) {
    mDataList.remove(position);
    isDataSetChange = true;
    Fragment fragment = mFragmentManager.findFragmentByTag(mTagList.get(position));
    mTagList.remove(position);
    if (fragment == null) {
        notifyDataSetChanged();
        return;
    }
    FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
    fragmentTransaction.remove(fragment);
    fragmentTransaction.commit();
    mFragmentManager.executePendingTransactions();
    notifyDataSetChanged();
}

注意:
其一”优化“示例,仅仅适用于以仅待创新某个 Fragment 的光景,关于动态删除
Fragment,该”优化“方案并无适用,也未引进以。

四、FragmentStatePagerAdapter

事先看作用:

FragmentStatePagerAdapter数据源刷新演示

简介

FragmentStatePagerAdapter
与 FragmentPagerAdapter 类似,这有限只类似都延续自 PagerAdapter。但是,和
FragmentPagerAdapter 不均等的是,FragmentStatePagerAdapter
只保留当前页面,当页面离开视线后,就见面让免除,释放其资源;而在页面需要展示时,生成新的页面(这与
ListView
的贯彻均等)。这种艺术的补就是是当所有大量之页面时,不必在内存中据为己有大量的内存。(参考自:FragmentPagerAdapter与FragmentStatePagerAdapter区别)

FragmentStatePagerAdapter 的贯彻和 FragmentPagerAdapter
有良充分分别,如果照搬上述 FragmentPagerAdapter
刷新数据的点子,你见面发现无啊问题(可以采取 FPagerAdapter11.java
测试)。

其他一样种植思路

只是,我于档次遭到实际上采用的时刻(Fragment
比较复杂,里面来网络任务相当)出现了 IllegalStateException,发生在
”fragmentTransaction.remove(f);“
时。当时寻觅了有些章没有缓解该问题,考虑到品种被之 Fragment
里面逻辑过多,就换思路,没有以此方面继续深究了。

要是,你吧是这样使 FragmentStatePagerAdapter 来动态改变 ViewPager 中
Fragment,并且于 remove Fragment 时遇上了
IllegalStateException。那么,你可以设想使用下的法子,先看代码(FSPagerAdapter
.java):

public class FSPagerAdapter extends FragmentStatePagerAdapter {

    private ArrayList<Fragment> mFragmentList;

    public FSPagerAdapter(FragmentManager fm, List<Integer> types) {
        super(fm);
        updateData(types);
    }

    public void updateData(List<Integer> dataList) {
        ArrayList<Fragment> fragments = new ArrayList<>();
        for (int i = 0, size = dataList.size(); i < size; i++) {
            Log.e("FPagerAdapter1", dataList.get(i).toString());
            fragments.add(FragmentTest.instance(dataList.get(i)));
        }
        setFragmentList(fragments);
    }

    private void setFragmentList(ArrayList<Fragment> fragmentList) {
        if(this.mFragmentList != null){
            mFragmentList.clear();
        }
        this.mFragmentList = fragmentList;
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return this.mFragmentList.size();
    }

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

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }
}

对应之测试 Activity 见 FSPagerAdapterActivity.java

点的代码挺简单,稍微解释一下实现思路:
1、缓存所有的 Fragment
用一个 List 将数据源对应之 Fragment 都缓存起来

2、更新数据源,刷新 Fragment
当起数据源更新的早晚,从 List 中取出相应的 Fragment,然后刷新 Adapter

3、删除数据时,删除 List 中对应的 Fragment
当数码源中删除某起时,将 List 中对应之 Fragment 也抹,然后刷新 Adapter

小结

有关 ViewPager 数据源刷新比较累的地方是于数据源中删除数据的状态,这和
ViewPager
的兑现方式有关,我们当解决该问题之时节要分开具体情况来用不同之方案。

方提供的方案也未是无微不至的,还有多供不应求,如果您在动用之过程中遇见了问题,那么要报告给我,大家一块儿完善。

这里要是探索关于 ViewPager 数据源刷新的题目,关于 ViewPager
的事无巨细使用不是本文重点,这里就是未干了。

花色地址

GitHub
私博客

参考

ViewPager
详解(二)—详解四大函数
pagerAdapter arrayList 数据清空,Item
不销毁的bug解决
ViewPager刷新单个页面的方法
ViewPager动态加载、删除页面
ViewPager+Fragment滑动界面,并举行缓加载【新版】
有关ViewPager的数据更新问题总结
Viewpager+fragment数据更新问题浅析
顺藤摸瓜源码解决android疑难有关题材1-Viewpager之notifyDataSetChanged无刷新
釜底抽薪fragment+viewpager第二软跻身的时光从不数量的题材
FragmentPagerAdapter刷新fragment最圆解决方案
Viewpager+fragment数据更新问题分析
FragmentPagerAdapter与FragmentStatePagerAdapter区别

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图