本网站(662p.com)打包出售,且带程序代码数据,662p.com域名,程序内核采用TP框架开发,需要联系扣扣:2360248666 /wx:lianweikj
精品域名一口价出售:1y1m.com(350元) ,6b7b.com(400元) , 5k5j.com(380元) , yayj.com(1800元), jiongzhun.com(1000元) , niuzen.com(2800元) , zennei.com(5000元)
需要联系扣扣:2360248666 /wx:lianweikj
ViewPager调用notifyDataSetChanged() 刷新问题解决方案
冷月葬花魂 · 514浏览 · 发布于2020-02-11 +关注

一、问题来由

ViewPager控件很大程度上满足了开发者开发页面左右移动切换的功能,使用非常方便。但是使用中发现,在删除或者修改数据的时候,PagerAdapter无法像BaseAdapter那样仅通过notifyDataSetChanged方法通知刷新View。有人提出一种解决方案:给Viewpager重新设置一遍适配器adapter,来达到刷新数据的目的。但是这种方法在大多数情况下,是存在问题的。

二、问题分析

为什么调用数据更新的方法,Viewpager却没有更新呢,我们跟进该方法的源代码看一下。

/**

 * This method should be called by the application if the data backing this adapter has changed

 * and associated views should update.

 */

public void notifyDataSetChanged() {

    mObservable.notifyChanged();

}

注释里说到,当附加在适配器上的数据发生变化时,应该调用该方法刷新数据。该方法调用了一个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();

         }

    }

}

这都不是重点,重点我们来看这个mObservers的类型是一个抽象类DataSetObserver,里面只有两个未实现的方法,都有谁使用了这个抽象类呢,快捷键 ctrl + alt + H ,在众多的调用者当中,我们发现了Viewpager的身影。进入Viewpager,我们终于找到了Viewpager中控制数据变更的重点方法dataSetChanged ,这个方法如下:

void dataSetChanged () {

        // This method only gets called if our observer is attached, so mAdapter is non-null.

 

        boolean needPopulate = mItems .size() < mOffscreenPageLimit * 2 + 1 &&

                mItems.size() < mAdapter.getCount();

        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, mAdapter.getCount() - 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();

        }

    }

重点看这样一行代码:

final int newPos = mAdapter.getItemPosition(ii.object);if (newPos == PagerAdapter.POSITION_UNCHANGED) {      continue ;
}

到这里我们就找到了解决这个问题的核心方法:getItemPosition()。官方对getItemPosition()的解释是:

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 orPOSITION_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

三、解决方案

根据上面的分析,我们可以尝试着修改适配器的写法,覆盖getItemPosition()方法,当调用notifyDataSetChanged时,让getItemPosition方法人为的返回POSITION_NONE,从而达到强制Viewpager重绘所有item的目的。

@Overridepublic int getItemPosition(Object object) {    return POSITION_NONE;
}


相关推荐

android下vulkan与opengles纹理互通

talkchan · 1178浏览 · 2020-11-23 10:37:39
Android 使用RecyclerView实现轮播图

奔跑的男人 · 2175浏览 · 2019-05-09 17:11:13
微软发布新命令行工具 Windows Terminal

吴振华 · 869浏览 · 2019-05-09 17:15:04
Facebook 停止屏蔽部分区块链广告

· 754浏览 · 2019-05-09 17:20:08
加载中

0评论

评论
分类专栏
小鸟云服务器
扫码进入手机网页