本文参考自: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来说的,如下图:
另外,还需要注意一下末尾的评论,如果有出现评论中的状况的: