RecyclerView重写ItemAnimator导致的Bug

最近有一个需求,用一个八宫格显示图片,后台不断发送图片过来,每个格子的图片定时刷新,同时做渐变切换的效果。

同事用RecyclerView+自定义渐变效果的ItemAnimator实现这个效果,具体来说就是每次要切换图片时,调用notifyItemChanged()对应的格子。

但是效果不如预期,经常会出现前一张图片没有完全变成0透明度,导致两张图片看起来像是透明叠加在一起。

这里简单说一下RecyclerView的局部刷新逻辑:当调用notifyItemChanged()时,会先从内部的缓存池找change类型的缓存ViewHolder(缓存池会保存很多类型的ViewHolder),如果没有,会调用Adapter的onCreateViewHolder()创建一个新的ViewHolder,然后将新的ViewHolder和原来对应的局部的ViewHolder传入ItemAnimator中的animateChange()方法,在这个方法内对新旧Holder执行相应动画,同时将新的Holder传入Adapter的onBindViewHolder方法中,最后RecyclerView将新的Holder替换旧的Holder,旧的Holder则存入缓存池中对应change类型的缓存里。

后来通过测试证实,如果调用notifyItemChanged()较慢时,通过打印可以看到,就是两个不同的ViewHolder实例在不断的互相替换;但是如果调用速度过快,后面就会变成新、旧Holder都是同一个Holder,导致动画异常。

事实上,在源码默认的DefaultItemAnimator中,可以看到在animateChange()方法里有判断新旧Holder是否一致,若一致则调用animateMove()方法;而自定义的ItemAnimator则没有实现该功能。

虽然最后的解决方法是不用ItemAnimator,而改用TransitionDrawable来实现效果。但需要注意的是,如果往后需要使用ItemAnimator,最好在DefaultItemAnimator的基础上改,因为这东西坑还是蛮多的,一个完整的ItemAnimator要写的代码也不少。

Flutter先导篇 The ABC of Dart Part 8 - 并发

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×