RecyclerView 刷新时图片会闪一下

本文探讨了解决RecyclerView在使用Glide加载图片时刷新闪烁的问题。通过调整RecyclerView的动画设置和Glide的缓存策略,成功消除了闪烁现象,提供了更流畅的用户体验。

最近遇到使用RecyclerView,Glide加载图片,当点击图片进行刷新,不管是局部刷新还是全部刷新的时候,都会使用glide重新加载图片,这时候如果glide加载图片的时候没设置好就会出现刷新的时候闪烁的问题,当然这是我出现的问题。
网上很多基本都是说recyclerview刷新闪烁是因为默认动画导致的mRecyclerView.setItemAnimator(new DefaultItemAnimator()),通过自定义动画修改代码

将DefaultItemAnimator类里的代码全部copy到自己写的动画类中,然后做一些修改。
首先找到private void animateChangeImpl(final ChangeInfo changeInfo) {}方法。
找到方法里这两句代码:

oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { ... }
newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).alpha(1).setListener(new VpaListenerAdapter() { ... }

替换成:

oldViewAnim.setListener(new VpaListenerAdapter() { ... }
newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).setListener(new VpaListenerAdapter() { ... }

也就是说分别去掉上述代码中的alpha(0)和alpha(1),然后保存。这个时候基本就打工告成了。最后在自己的RecyclerView中进行如下调用mRecyclerView.setItemAnimator(new NoAlphaItemAnimator());,再跑起来,bug完美解决。

然而我这样做了,并没有什么卵用
还有一种直接方法,setSupportsChangeAnimations(false)直接取消动画

((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(false); 

都试过并没有解决刷新闪烁的问题。后来发现原来是glide设置了跳过内存缓存skipMemoryCache(true)导致的。
设置成false

	Glide
                .with(context)
                .load("imagePath")
                .skipMemoryCache(false)
                .thumbnail(0.5f)
                .fitCenter()
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .dontAnimate()
                .into(holder.image);

<think>嗯,用户问的是关于AndroidRecyclerView的Adapter调用notifyDataSetChanged列表会烁的问题。这个问题我之前也遇到过,得仔细想想怎么解决。 首先,得了解为什么调用notifyDataSetChanged会导致烁。可能的原因是每次调用这个方法,整个列表项都会被重新绑定,导致视图重新绘制,如果数据变化较大,就会有明显的烁效果。这候需要找替代方法,或者优化数据更新的方式。 然后,想到RecyclerView的Adapter有其他更细粒度的通知方法,比如notifyItemChanged、notifyItemInserted等。这些方法只更新特定的位置,而不是整个列表,应该可以减少烁。用户可能是在全部数据更新用了全局刷新,换成局部更新可能会好很多。 另外,检查一下数据更新的方式是否正确。如果在更新数据,没有保持数据集的稳定性,比如每次都创建新的列表,可能会导致Adapter认为整个数据都变了。这候应该保持数据集的引用不变,只更新里面的内容,或者使用DiffUtil来处理差异更新。 DiffUtil是Android提供的工具类,可以计算两个数据集的差异,并自动调用合适的notify方法。这样既能提高效率,又能避免不必要的刷新。比如用DiffUtil.Callback来比较新旧数据,然后通过DiffUtil.DispatchResultToAdapter来应用更新。 还有,动画的问题也可能导致烁。默认情况下,RecyclerView的项可能有变更动画,可以尝试关闭默认的动画,看看是否有效。比如设置itemAnimator为null,或者在更新数据禁用动画。 另外,检查是否有多个地方同调用了notifyDataSetChanged,或者数据被频繁更新,导致界面不断刷新。这种情况下需要优化数据更新的频率,合并多次更新,或者使用防抖机制。 还有一种情况是数据绑定的布局问题。如果在onBindViewHolder中某些视图的状态没有正确重置,比如图片加载的占位符,可能会导致短暂烁。确保在绑定数据,所有视图都正确设置了新的数据,并清除旧的状态。 总结一下,可能的解决方案包括使用局部刷新、DiffUtil、关闭动画、优化数据更新方式等。需要根据具体情况选择合适的办法。</think>在 RecyclerView 中使用 `notifyDataSetChanged()` 导致列表烁的常见原因及解决方案: 1. **根本原因分析** - `notifyDataSetChanged()` 会强制所有 Item 重新绑定数据 - 导致视图层完全重建,失去原有动画和状态保持能力 - 当数据变化较大会产生视觉烁 2. **推荐解决方案** **方案一:使用 DiffUtil(最佳实践)** ```kotlin class MyDiffCallback( private val oldList: List<Item>, private val newList: List<Item> ) : DiffUtil.Callback() { override fun getOldListSize() = oldList.size override fun getNewListSize() = newList.size override fun areItemsTheSame(oldPos: Int, newPos: Int): Boolean { return oldList[oldPos].id == newList[newPos].id } override fun areContentsTheSame(oldPos: Int, newPos: Int): Boolean { return oldList[oldPos] == newList[newPos] } } // 使用示例 val diffResult = DiffUtil.calculateDiff(MyDiffCallback(oldList, newList)) adapter.submitNewList(newList) // 需要自行实现列表更新方法 diffResult.dispatchUpdatesTo(adapter) ``` **方案二:局部刷新(针对特定修改)** ```kotlin // 插入新项 adapter.notifyItemInserted(position) // 删除项 adapter.notifyItemRemoved(position) // 更新单个项 adapter.notifyItemChanged(position) // 批量更新 adapter.notifyItemRangeChanged(startPos, itemCount) ``` 3. **优化技巧** - **保持数据引用**:不要每次创建新列表,应保持列表对象引用不变 ```kotlin // 推荐做法 originalList.clear() originalList.addAll(newData) ``` - **关闭默认动画**(临方案) ```kotlin (recyclerView.itemAnimator as? SimpleItemAnimator)?.supportsChangeAnimations = false // 或完全禁用 recyclerView.itemAnimator = null ``` - **稳定ID设置** ```kotlin override fun getItemId(position: Int): Long { return dataList[position].id // 确保每个item有唯一稳定ID } // 在Adapter构造函数中设置 setHasStableIds(true) ``` 4. **常见误区** - ❌ 每次更新都创建新列表: ```kotlin // 错误做法 adapter.list = newList.toMutableList() adapter.notifyDataSetChanged() ``` - ✅ 正确做法: ```kotlin with(adapter.list) { clear() addAll(newList) } // 配合DiffUtil或局部刷新使用 ``` 5. **性能对比** | 方法 | 间复杂度 | 动画保留 | 烁风险 | |---------------------|-------------|----------|----------| | `notifyDataSetChanged` | O(N) | ❌ | 高 | | `DiffUtil` | O(N log N) | ✅ | 低 | | 局部刷新 | O(1) | ✅ | 无 | 建议优先使用 DiffUtil 配合 ListAdapter 实现自动差异计算: ```kotlin class MyAdapter : ListAdapter<Item, ViewHolder>(MyDiffCallback()) { // 自动处理列表更新 fun submitNewList(list: List<Item>) { submitList(list.toMutableList()) } } ``` 通过上述优化,可以消除列表烁问题,同提升滚动流畅度和内存效率。实际项目中推荐结合 Data Binding 或 View Binding 使用,进一步优化视图绑定性能。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值