【转载】【Android】详解7.0带来的新工具类:DiffUtil

本文参考自:http://blog.csdn.net/zxt0601/article/details/52562770

(先说点题外话,这博主很不错了,他的文章在hongyangAndroid (鸿洋)的公众号的发布过多次了,文章不仅有技术含量,而且文笔很细腻)


这次学习的是一个与RecyclerView有关的工具类——DiffUtil,具体的内容请看上文。我在这里主要是就文章的一些点提出自己的见解:

1、在模拟刷新的onRefresh()方法中。有这么一段代码:

            mNewDatas = new ArrayList<>();
            for (TestBean bean : mDatas) {
                mNewDatas.add(bean.clone());//clone一遍旧数据 ,模拟刷新操作
            }
            //mNewDatas.addAll(mDatas); //++++++++++
            mNewDatas.add(new TestBean("赵子龙", "帅", R.drawable.pic6));//模拟新增数据
            mNewDatas.get(0).setDesc("Android+++++");
            mNewDatas.get(0).setPic(R.drawable.pic7);//模拟修改数据
            TestBean testBean = mNewDatas.get(1);//模拟数据位移
            mNewDatas.remove(testBean);
            mNewDatas.add(0,testBean);

在注释里有讲解,clone一遍旧数据 ,模拟刷新操作,这里需要注意,新的数据需要深度clone(生成一个新的与原来TestBean实例具有相同内容的成员变量的实例,如果不懂请看演示图),否则mNewDatas与mDatas对于“一个相同的TestBean实例(成员变量的内容相同)”存在同一引用,从而导致改变mNewDatas的某一项的成员变量的内容,由于存在统一引用,mDatas中的那一项也会跟着改变,因此areContentsTheSame()是不起作用的, 大家也可以自己去尝试一下,就像我注释掉的那行代码(把原来的操作注释掉),虽然是new了一个新的mNewDatas,但是通过mNewDatas.addAll(mDatas)方法填充的数据,在未做其他操作的前提下,mNewDatas与mDatas中的每一项数据都具有相同的引用,说白了就是同一东东。(其实这一点在文章末尾也有提到,但具体的就是上面的意思)。(题外话:这里是在用空间换效率)
这里写图片描述

演示图(第一张的为正确的,第二张为非正确的):
这里写图片描述

这里写图片描述

2、 在使用博主提供的Demo时,如果是按照文章的顺序一步一步看下去的,则在第2步DiffUtil的简单用法 时,想要运行demo体验演示效果的话,需要把DiffCallBack.java中的getChangePayload(int oldItemPosition, int newItemPosition)方法与DiffAdapter中的onBindViewHolder(DiffVH holder, int position, List<Object> payloads)方法注释掉,再去运行,因为这是第3部分DiffUtil的高级用法的内容了。开始我就没有注意到,就直接运行了,然后就没有体验到博主所说的“白光一闪”。(搞得我一直以为是我眼花,看不出来#_#)
这里写图片描述


番外篇:

在前面的文章中有提到过一个名词“定向刷新”,如果对这个有疑惑的,可以看看这个:
【Android】 RecyclerView、ListView实现单选列表的优雅之路.

在这里面,有用实际了代码讲解什么是“定向刷新”。
值得注意的是在三 ListView 方案一览:2 ListView里寻找优雅之路:中,核心代码如下(从考虑了HeaderView的情况 这里就可以体现出作者的细腻):

                //如果 当前选中的View 在当前屏幕可见,且不是自己,要定向刷新一下之前的View的状态
                if (position != mSelectedPos) {
                    int firstPos = mLv.getFirstVisiblePosition() - mLv.getHeaderViewsCount();//这里考虑了HeaderView的情况
                    int lastPos = mLv.getLastVisiblePosition() - mLv.getHeaderViewsCount();
                    if (mSelectedPos >= firstPos && mSelectedPos <= lastPos) {
                        View lastSelectedView = mLv.getChildAt(mSelectedPos - firstPos);//取出选中的View
                        CouponVH lastVh = (CouponVH) lastSelectedView.getTag();
                        lastVh.ivSelect.setSelected(false);
                    }
                    //不管在屏幕是否可见,都需要改变之前的data
                    mDatas.get(mSelectedPos).setSelected(false);

                    //改变现在的点击的这个View的选中状态
                    couponVH.ivSelect.setSelected(true);
                    mDatas.get(position).setSelected(true);
                    mSelectedPos = position;
                }

在上面的代码中,有View lastSelectedView = mLv.getChildAt(mSelectedPos - firstPos); ,这里是为了获取先前被选中的view,这里用到了ListView的getChildAt()方法,其作用就是取得在屏幕上可见的items中指定index的view,不过这里index基数为0,即第一个可见的item的index为0,依次类推,而不是基于整个ListView的第一个item来说的,如下图:
这里写图片描述

另外,还需要注意一下末尾的评论,如果有出现评论中的状况的:
这里写图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章