美文网首页
【Android零散知识】PageAdapter notifyD

【Android零散知识】PageAdapter notifyD

作者: wenld_ | 来源:发表于2017-11-22 13:57 被阅读378次
    人生得意须尽欢,
    桃花坞里桃花庵。
    

    Question:

    最近在 《开发一款商业级Banner控件》,其中碰到了 调用 PageAdapter.notifyDataSetChanged() 页面不刷新问题,让我非常之郁闷,具体的问题是这样的:当我改变数据源时 调用notifyDataSetChanged时,当前页面以及缓存页面的内容不刷新。

    如图: 在数据改变的情况下,我们的界面并没有刷新。 没办法 去看看源码吧。


    Reson:

    那么我们就先来看看notifyDataSetChanged()的源码吧。

    1、刷新开始

    PageAdapter.class
    
        public void notifyDataSetChanged() {
            synchronized (this) {
                if (mViewPagerObserver != null) {
                    mViewPagerObserver.onChanged();
                }
            }
            mObservable.notifyChanged();
        }
        public void unregisterDataSetObserver(DataSetObserver observer) {
            mObservable.unregisterObserver(observer);
        }
    
        void setViewPagerObserver(DataSetObserver observer) {
            synchronized (this) {
                mViewPagerObserver = observer;
            }
        }
    

    ok,看到这就知道这是个观察者模式,而且成员变量mViewPagerObserver是在 setViewPagerObserver方法中设置进来的, 那么现在 找到这个'mViewPagerObserver' 是个什么东西以及mViewPagerObserver.onChanged()方法都做了些什么

    2、PagerObserver 以及 dataSetChanged()
    可以看到 在ViewPager当中我们创建了 PagerObserver并调用了 mAdapter.setViewPagerObserver(mObserver); 所以我们的 mViewPagerBoserverPagerObserver; 它又调用了dataSetChanged()方法

    ViewPager.class
        public void setAdapter(PagerAdapter adapter) {
            ....
            if (mAdapter != null) {
                if (mObserver == null) {
                    mObserver = new PagerObserver();
                }
              //监听adapter
               mAdapter.setViewPagerObserver(mObserver);
    }
    
    // viewPager内部类
        private class PagerObserver extends DataSetObserver {
            PagerObserver() {
            }
    
            @Override
            public void onChanged() {
              // 数据改变时调用这个方法
                dataSetChanged();
            }
            @Override
            public void onInvalidated() {
                dataSetChanged();
            }
        }
    

    3、dataSetChanged

        void dataSetChanged() {
            // This method only gets called if our observer is attached, so mAdapter is non-null.   只给observer调用
           // 拿到数据数量
            final int adapterCount = mAdapter.getCount();
            mExpectedAdapterCount = adapterCount;
            //判断是否需要填充
            boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1
                    && mItems.size() < adapterCount;
            //拿到当前选中的item下标
            int newCurrItem = mCurItem;
    
            boolean isUpdating = false;
            //循环mitems
            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;
                }  
              ...
        }
    
    

    可以看到 大致的意思是:循环遍历视图上所有的item, 并通过adapter.getgetItemPosition方法 拿到一个newPos ,该值有两种状态 一种:PagerAdapter.POSITION_UNCHANGEDPagerAdapter.POSITION_NONE ,如果为PagerAdapter.POSITION_UNCHANGED状态那么就不刷新itemView,否则 先销毁现有的itemView再重新创建一个新的itemVIew;

    所以看到这里 就明白了 为什么调用notifyDataSetChanged没有刷新页面。 直到这里那么我们就可以解决我们的问题了。

    solve

    这里的解决思路是,在我调用notifyDataSetChanged 方法时 ,将 getgetItemPosition 的返回值设置为PagerAdapter.POSITION_NONE, 这样所有的 item视图都会刷新了。

    具体代码是这样:
    自定义PageAdapter

        public boolean myNotify = false;
        @Override
        public int getItemPosition(Object object) {
            if (!myNotify) {
                return super.getItemPosition(object);
            } else {
                return POSITION_NONE;
            }
        }
        public void notifyDataSetChanged(boolean isRefresh){
            myNotify=isRefresh;
            super.notifyDataSetChanged();
            myNotify=false;
        }
    

    调用时

            mAdapter.notifyDataSetChanged(true);
    

    Question2:

    强制刷新后transformer错乱问题


    还是看源码【Android源码解读】ViewPager; 终于找到了问题
    最后排查原因,是因为强制刷新后,调用 transformer 在requestLayout之前,而我们新建的view,在onLayout之前 view.left=0;所以 调用transformer时数据是不对的。

    最后如下解决:

    // ViewPager 
       
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            super.onLayout(changed, l, t, r, b);
    
            if (transformer != null) {
                final int scrollX = getScrollX();
                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) continue;
                    final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth();
                    transformer.transformPage(child, transformPos);
                }
            }
        }
    

    希望我的文章不会误导在观看的你,如果有异议的地方欢迎讨论和指正。
    如果能给观看的你带来收获,那就是最好不过了。

    人生得意须尽欢, 桃花坞里桃花庵
    点个关注呗,对,不信你点试试?

    相关文章

      网友评论

          本文标题:【Android零散知识】PageAdapter notifyD

          本文链接:https://www.haomeiwen.com/subject/amlmmxtx.html