你可能不知道的在RecyclerView中实现局部刷新的技巧
写在前面
在上一年的时候我曾经写了一篇<<在RecyclerView中实现定点刷新>>的文章介绍了如何使用DataBinding框架进行局部刷新。时隔将近一年,期间我也换了一份工作,在新公司里并没有使用到DataBinding,所以如果想进行局部刷新ui,可能需要使用较早的adapter.notifyItemChanged(pos)
。
近期在做一个功能的时候,发现有一个比较简便可行的方法,可以达到局部刷新的效果。
那么方法是什么呢?
其实思考🤔一下,如果要更新一个TextView的文本,需要怎么做呢?
答案非常简单:那就是找到这个TextView,然后调用它的setText
方法。
代码的话,可能是这样 :
findViewById<TexView>(R.id.titleTv).text = "title"
上面的是指普通的View,那么在RecyclerView呢?
其实答案差不多,我们只需要找到对应的ItemView
或者它的ViewHolder
,然后调用对应的渲染ui的方法就行了。先看看效果:
那应该怎么做呢?
一个简单的方法
其实RecyclerView
已经提供了根据position
获取ViewHolder
这个功能。
从方法里可以看到RecyclerView
会for循环去找holder,然后比较位置,如果不为null,且没有被移除,那么代表可以找到了,反之则为null。
那怎么找呢?
其中childCount
是通过 this.mChildHelper.getUnfilteredChildCount()
得到的。
其最终会调用RecyclerView的getChildCount()
方法,返回的结果表示可见的item个数。比如当前可见的是8个,那么childCount即是8,所以你想获取超过屏幕最大Index的ViewHoler,那么就会返回null。比如当前最大可见的position为13,如果你想找第11个,能够获取到,但是找第15个,那么会返回null。
接着我们来拆解获取ViewHolder的方法,如下所示:
getChildViewHolderInt(this.mChildHelper.getUnfilteredChildAt(i));
首先会通过getUnfilteredChildAt
获取到index对应的view。这个方法最后也是调用的RecyclerView的getChildAt(offset)方法。
找到View之后,再用getChildViewHolderInt(view)
获取对应的ViewHolder,其内部实现如下:
即通过LayoutParams
获取到相应的ViewHolder。
而将ViewHolder赋值给LayoutParams的过程出现在RecyclerView的getViewForPosition(pos)
方法中,最终会被LayoutManager调用。
回到主题,现在我们获取到了想要的ViewHoler
,而且也知道了当前的Position
,那么只需要再调用Adapter的
onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int)
即可。
当然因为在Adapter中也能获取到RecyclerView,所以可以将更新的方法放入到Adapter中。
image数据变化的时候,调用notifyItemUpdate(pos:Int)
即可,可以说是很简单了。
写在后面
如果要说再优化的话,当然也有继续优化的点,比如减少无用的更新,或者说能在子线程通知更新UI,当然这些都是后话,以后再来完善。
GitHub示例:https://github.com/ditclear/BindingListAdapter
==================== 分割线 ======================
如果你想了解更多关于MVVM、Flutter、响应式编程方面的知识,欢迎关注我。
你可以在以下地方找到我:
简书:https://www.jianshu.com/u/117f1cf0c556
掘金:https://juejin.im/user/582d601d2e958a0069bbe687
Github: https://github.com/ditclear
image