问题记录:图片加载快速滑动闪动问题
此问题本身处理起来还算简单,但是因为顺手做了两部分code优化,导致此问题多花费了一些精力,这里记录下,方便后续查看
前置条件介绍:
- 使用recycleview显示图片列表;
- 多线程加载图片,获取后给到UI线程显示;
问题描述:
- 快速滑动图片列表,后续加载的图片会出现闪烁,且在列表中会发现有重复情况;
- 修复上述问题后,发现viewPager和RecyclerView快速向后滑动,约在第17张之后会出现偶尔几张加载不出来的情况;
问题分析:
问题一现象分析:
- 闪烁说明此时该item有快速刷新图片(可能是不同图片);
- 重复说明load图片完成后到show这张图片的逻辑中有问题(而此处为了防止图片显示到错误的item是有做判断的:将image path添加到view tag中,显示时判断);
怀疑点:
则此问题已经非常清晰了,一定是获取图片后显示到对应的imageview时的逻辑处理有问题,则继续check这部分流程:从code逻辑来看imageview的对象和path是绑定的,也就是说正常情况下并不会出现一个imageview上显示多个图片的情形;
- 考虑到快速滑动的应用场景,则因为此处没有对加载图片任务添加cancel机制,所以会导致快速滑动大量图片后,任务阻塞,最后需要显示的图片需要一定时间才可以显示;
- 考虑到是recyclerView 作为图片列表,在此场景中需要确认其回收缓存机制,如果该imageview对象被复用了的话,则上述现象就可以说通了;
证实猜测:
则在adapter中添加log信息确认上述猜测:
- 确认recyclerView 有维持多少个item;
- loadimage时打印imageview和path的内容;
- show image时打印viewTag和path,确认此逻辑是否生效;
通过上述打印信息确认:
- recyclerView 维持10个item,当有滑动到第11个item时会复用之前的内容;
- 证实重复显示的view确实是因为复用了imageview
- 上述判断逻辑生效,但是此部分需要添加一个逻辑,即在复用该item时要先设置图片占位符将该item中图片刷新
问题说明:
- 问题原因:recyclerView的复用机制,在imageview初始化时需要刷新其内容;
- 解决措施:
- 每个item初始化时设置图片占位符刷新imageview显示内容;
- 考虑load图片和show图片是异步的,需要添加判断,此处使用path作为判断依据;
- 每个item初始化时设置图片占位符刷新imageview显示内容;
问题二现象分析:
图片没有刷新出来则需要考虑这个path中是否有逻辑异常:
- 图片加载过程(在修改上述问题时,顺手优化了loadImage的code结构)
- 图片显示过程,上述adapter中show图片的逻辑是否有异常
- item刷新过程:1. recyclerView滑动;2. viewpager滑动时对应recyclerView位置切换逻辑;
事实上此部分原因有两块:上述过程1和3都有问题;
- 图片加载过程中,添加workqueue,并在此处添加了重复判断,如果此图片已经在队列中则不再插入,但是由于此处使用imageView判断,而imageView是会复用的,所以这里如果被复用了很可能导致后续的image没有加入workQueue,则最终显示效果为部分图片未刷新;
- Item刷新过程中,由于需要对selectItem添加不同的背景,所以此处维护一个list用于保存select状态,在viewPager或者click item时notify list做对应的逻辑判断,而此处使用notifyDataSetChange函数(刷新所有visiable item),则每次切换图片都会添加5个任务给到工作线程,极大的加大了上述问题复现的可能性;
处理方案:
- 针对上述原因一,将查重判断的依赖从imageview修改为key(isThmus + path)
- 针对上述原因二,修改selectItem背景更新逻辑,去除队列,而是在adapter中添加一个变量用于标记被选择的position,切换selectItem时更新该值,并且notify逻辑修改为:1. 切换时仅更新两个需要修改的item;2. 针对控件刷新而不去重新load图片;
则上述问题处理完成