在RecyclerView的ViewHolder中使用Lottie动画滚动帧率过低,寻求解决方案
嘿,这种RecyclerView搭配Lottie动画导致滚动掉帧的问题我之前踩过不少坑,哪怕暂停动画还是卡的情况也遇到过,给你几个亲测有效的解决方案:
1. 优化Lottie的缓存与预加载策略
Lottie默认的缓存机制有时候不足以应对RecyclerView的快速复用场景,手动强化缓存能大幅降低CPU开销:
- 给LottieDrawable设置强缓存策略,让它把每一帧都缓存成Bitmap,滚动时直接复用无需实时解析:
lottieView.getLottieDrawable().setCacheStrategy(LottieDrawable.CacheStrategy.STRONG); - 预加载动画资源:把常用的Lottie动画在App启动时就解析好
LottieComposition,存在全局缓存里,ViewHolder绑定的时候直接复用,避免每次创建ViewHolder都重复解析JSON文件:// 在Application或全局单例中预加载 LottieCompositionFactory.fromRawRes(context, R.raw.your_anim) .addListener(composition -> { GlobalLottieCache.put("anim_key", composition); }); // 在ViewHolder中使用 LottieComposition composition = GlobalLottieCache.get("anim_key"); if (composition != null) { lottieView.setComposition(composition); }
2. 严格管理ViewHolder的动画状态
很多时候“暂停动画后仍卡顿”,是因为旧的动画实例在后台偷偷运行,或者复用ViewHolder时状态没重置:
- 在
onViewRecycled中彻底暂停并重置动画,避免复用残留状态:@Override public void onViewRecycled(@NonNull YourViewHolder holder) { super.onViewRecycled(holder); holder.lottieView.pauseAnimation(); holder.lottieView.setProgress(0f); // 重置到初始帧 // 可选:如果用了自定义监听器,记得移除避免内存泄漏 holder.lottieView.removeAllUpdateListeners(); } - 监听RecyclerView滚动状态,滚动时暂停所有可见动画,停止后再恢复播放:
(注:recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); for (int i = 0; i < recyclerView.getChildCount(); i++) { View child = recyclerView.getChildAt(i); YourViewHolder holder = (YourViewHolder) recyclerView.getChildViewHolder(child); if (newState == RecyclerView.SCROLL_STATE_IDLE) { // 仅播放完全可见的item动画 if (isItemFullyVisible(recyclerView, holder.getAdapterPosition())) { holder.lottieView.playAnimation(); } } else { holder.lottieView.pauseAnimation(); } } } });isItemFullyVisible需要自己实现,判断item是否完全出现在屏幕内)
3. 降低动画本身的复杂度
如果动画本身太“重”,再怎么优化也会有压力:
- 用Lottie编辑工具精简动画:删除不必要的图层、把帧率从60降到30(视觉差异极小)、压缩JSON文件大小;
- 缩小动画渲染尺寸:给LottieView设置
setScale(0.8f),降低渲染的Bitmap分辨率,减少内存和GPU开销; - 避免使用透明度过高的图层:大量半透明元素会增加GPU的混合计算压力。
4. 硬件加速与渲染优化
- 确保LottieView开启硬件加速:在布局XML中添加
android:hardwareAccelerated="true"(默认开启,但如果父布局禁用了需要手动开启); - 给LottieView设置硬件层渲染:把动画渲染到硬件纹理上,滚动时直接复用纹理,减少重绘:
注意:硬件层会占用更多内存,如果列表中有大量Lottie同时显示,需要权衡内存占用和流畅度。holder.lottieView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
5. 排查隐藏的性能消耗
- 用Android Studio Profiler查看CPU占用:如果滚动时CPU使用率很高,看看是不是有Lottie的后台解析线程在持续运行,或者其他无关逻辑占用资源;
- 检查内存泄漏:如果旧的ViewHolder没有被回收,对应的Lottie资源也会一直占用内存,用LeakCanary工具排查泄漏点。
这些方案我在多个项目里实践过,组合起来基本能解决滚动帧率低的问题,你可以根据自己的场景逐步尝试~
内容的提问来源于stack exchange,提问作者Miguel Barcelos
相关产品推荐
相关产品推荐

