0%

RecyclerView的notifyItemChanged引出的问题

   因项目要求,设计类似抖音的视频列表播放功能。在权衡之后,采用ViewPager2 + ExoPlayer 来实现,由于直接这样使用会引起视频播放混乱的问题,即划入下一个视频的时候,上一个视频还在播放,导致同一时刻多个视频同时播放。因此,我们设定一个单例的 mPlayer ,动态地设置给 PlayView,通过在onPageSelected 回调中,调用 notifyItemChanged 方法,刷新当前的item ,让它的标志 play = true,这样让它获取单例的 player ,从而实现播放。

  还有,在每个 item 里面需要有个dialog,点击这个item上的某个位置就弹出来,并且,如果第 0 个item 符合某个条件,那么进入视频列表页面就会弹出dialog。这时候,诡异的问题就来了,在某个测试版本,进入视频列表页面之后,弹出了一个dialog,但是感觉这个dialog上面会有一个蒙层,点击之后,这个蒙层才会消失,之后,该页面的所有按钮才能点击 !也就是测试所提出的,按钮需要点击两次才有效!这就奇怪了,通过LayoutInspector 也只能看到一个dialog浮在内容上(事实上这是使用不熟导致的,因为看起来,比如 ActivityA 中有3个dialog,那么在选择process的时候,会有3个 ActivityA 在那,所以应该是每有一个window都会展示一下这个activity,所以那时候应该是选了Activity,但是由于内容是一样的,所以看不出来)。

  但是通过打断点,发现同一个视频 id 生成了,在 itemView 中setData 3次,其实 2次是可以理解的 (数据刚加载的时候一次,在 notifyItemChanged 的一次);与此同时,发现同一个视频 id 出现在两个 itemView 中,这就很奇怪了,并且,前两次 是 itemView1 ,在 notifyItemChanged 之后,id 就出现在了 itemViewB 中了!如果没有看过源码的话,这时候应该颠覆了认知了,因为 notifyItemChanged 应该只刷新当前 item 才对,怎么会创建了一个新的 itemView 呢?

  这个问题到这里,其实可以解释得通了:由于第0个视频满足刚进入页面就需要弹dialog,所以弹了一次;这时候,由于第 0 个视频又被承载到了新的 itemView 上,创建了新的View ,所以又 弹出来了一次,也就是说,上面那个阴影是一个dialog。

  找到问题之后,再搜了下,发现如果 RecyclerView 默认带有动画的情况下,notifyItemChanged 会创建一个新的ViewHolder !难怪,那理论上,如果我去掉RecyclerView的动画,应该问题就解决了,于是有了如下代码:

1
2
3
4
5
//Adapter
override fun onAttachedToRecyclerView(rv: RecyclerView) {
super.onAttachedToRecyclerView(rv)
rv.itemAnimator = null
}

果然可以了!现在来总结以下问题:

由于默认的动画导致刷新单个item的时候创建了新的ViewHolder, 从而引起 Dialog 再弹了一次,两个重叠在一起了,解决方案就是将 RecyclerView 的动画去掉

以上内容参考资料腾讯云csdn的博客

谢谢你的鼓励