Android -- 处理ViewPager的notifyDataSetChanged无刷新

Viewpager在调用notifyDataSetChanged()时,界面无刷新

Viewpager在调用notifyDataSetChanged()时,界面无刷新,它确实影响我们功能的实现了。可能选择为Viewpager重新设置一遍适配器adapter,达到刷新的目的。但是这种方法在大多数情况下,是有问题的。

查看方法

super.notifyDataSetChanged()调用的是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() {
        mObservable.notifyChanged();
    }

注释里说到,当附加在适配器上的数据发生变化时,应该调用该方法刷新数据。该方法调用了一个mObservable .notifyChanged();

我们继续跟进这个方法,进入DataSetObservable类中,发现这样一段代码:

/**
     * 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,里面只有两个未实现的方法,都有谁使用了这个抽象类呢,其中我们发现了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 ;
   }

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 returnsPOSITION_UNCHANGED.

意思是如果item的位置如果没有发生变化,则返回POSITION_UNCHANGED。如果返回了POSITION_NONE,表示该位置的item已经不存在了。默认的实现是假设item的位置永远不会发生变化,而返回POSITION_UNCHANGED

解决方案

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

class SearchAdapter extends PagerAdapter {

     private int mChildCount = 0;

     @Override
     public void notifyDataSetChanged() {
           mChildCount = getCount();
           super.notifyDataSetChanged();
     }

     @Override
     public int getItemPosition(Object object)   {
           if ( mChildCount > 0) {
           mChildCount --;
           return POSITION_NONE;
           }
           return super.getItemPosition(object);
     }

}

我是天王盖地虎的分割线

时间: 2024-08-06 11:51:27

Android -- 处理ViewPager的notifyDataSetChanged无刷新的相关文章

##解决 ViewPager 调用 notifyDataSetChanged()无刷新:原理、解决办法##

一.原理 转自:http://www.cnblogs.com/maoyu417/p/3740209.html 转载 http://www.67tgb.com/?p=624 最近项目结束,搞了一次代码分享.其中一位同学分享了一下自己在解决问题过程中的一些心得体会,感觉受益匪浅.整理出来,分享给大家. 建议使用自己编译的android os和虚拟机,这样就可以调试android系统中的任何组件.简单说来,深入android源码,去寻找解决问题的答案.这事儿说起来简单,实际做起来还是有些难度的.我也曾

Android viewPage notifyDataSetChanged无刷新

转载 http://www.67tgb.com/?p=624 最近项目结束,搞了一次代码分享.其中一位同学分享了一下自己在解决问题过程中的一些心得体会,感觉受益匪浅.整理出来,分享给大家. 建议使用自己编译的android os和虚拟机,这样就可以调试android系统中的任何组件.简单说来,深入android源码,去寻找解决问题的答案.这事儿说起来简单,实际做起来还是有些难度的.我也曾经尝试着去看过,没看一会儿就晕了. 所以还是有针对性的去看源码,效率会高一些. 废话不多说,先看第一个示例.

ViewPager 调用notifyDataSetChanged()不刷新内容的问题

banner广告条,刷新数据后,调用ViewPager的notifyDataSetChanged()方法,没法马上改变图片.但是如果设置自动轮播,过了预加载的图片,就是显示新的了.查了一下,这边有一篇转载的文章 http://www.cnblogs.com/maoyu417/p/3740209.html.看着挺麻烦的,没试.自己想了个省事的方法. 就是这样: pagerAdapter.notifyDataSetChanged(); viewPager.setCurrentItem(3); 刷新之

android ListView中使用notifyDataSetChanged()不刷新

private List<Navi> mRouteList; 1. 设置Adapter private void initData() { mRouteList = new ArrayList<Route>(); mRouteList.clear(); mAdapter = new CarRouteAdapter(getActivity(), mRouteList); mListView.setAdapter(mAdapter); } 2. 获取数据,刷新listview priv

【JS】ajax 实现无刷新文件上传

一.摘要 最近在做个东西,需要实现页面无刷新文件上传,目前看到的方法有两种 1) 通过隐藏iframe 实现页面无刷新,适用于不关心上传结果 1 <form target="hiddenFrame" method="post" enctype="multipart/form-data" action='xx'> 2 <input value=""/> 3 <iframe name="hi

Android listview viewpager解决冲突 滑动

Android listview viewpager 滑动 跳动 冲突解决 ListView中嵌套ViewPage有或者滑动手势冲突解决 在listview 上使用 addHeaderView 在第一栏添加 viewpager 当做header 如: 当触发 滑动事件 的时候容易引起 滑动冲突    (比如斜着滑动viewpager  的时候 listview会跳动) 特别是在  下拉刷新或者上拉加载 的时候 , 组件可能会传递到viewpager当中 查阅了很多的帖子  发现修改起来都非常麻烦

Android ListView下拉/上拉刷新:设计原理与实现

 <Android ListView下拉/上拉刷新:设计原理与实现> Android上ListView的第三方开源的下拉刷新框架很多,应用场景很多很普遍,几乎成为现在APP的通用设计典范,甚至谷歌官方都索性在Android SDK层面支持下拉刷新,我之前写了一篇文章<Android SwipeRefreshLayout:谷歌官方SDK包中的下拉刷新>专门介绍过(链接地址:http://blog.csdn.net/zhangphil/article/details/4696537

Android PullToRefresh (GridView 下拉刷新上拉加载)

做这个需要自己去git hub上下载个pull-to-refresh 里面有个library为依赖包自己导到自己的项目中 (下载地址:https://github.com/chrisbanes/Android-PullToRefresh) activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.

android官方自带下拉刷新功能

最近想写下拉刷新功能,网上找的第三方框架最著名的pullToRefresh也早在2013年停止维护了,偶然间发现谷歌公司早已推出了自家的下拉刷新功能,位于v4包中,效果请看下图: 使用的就是android.support.v4.widget.SwipeRefreshLayout控件,使用方法也很简单,首先把需要下拉刷新的listView放入SwipeRefreshLayout中,代码如下: xml布局: <android.support.v4.widget.SwipeRefreshLayout