上周在老项目里加功能,遇到个诡异的问题:RecyclerView 滑动卡顿,但数据量很小,就几十条。
记录一下排查过程,免得以后忘了。
项目背景
2019 年启动的项目,中间换过几波人维护。消息列表用 RecyclerView,每个 Item 里有头像、文字、和一个自定义的圆形进度条。
现象
滑动时不跟手,肉眼可见掉帧。GPU 渲染模式打开,柱状图大量超过绿线。
但奇怪的是:同样的布局,其他页面不卡。只有这个消息列表卡。
排查
先怀疑数据
打 Log,数据源 30 多条,走 DiffUtil,不是这里。
再怀疑图片
Glide 配置正常,有占位图、大小限制、内存缓存。注释掉图片加载,还是卡。
最后怀疑自定义 View
逐个注释 Item 里的 View,注释到 CircleProgressView 时,卡顿消失。
但进度条是 GONE 的
列表里没有正在下载的消息,进度条 visibility = GONE,不应该影响性能才对。
看代码发现问题
CircleProgressView 的构造函数里:
public CircleProgressView(Context context) { super(context); init(); startAnimation(); // 这里直接启动了动画 }
ValueAnimator 在初始化时就启动了,不管是否可见。虽然 onDraw 里没绘制,但动画一直在后台跑,消耗 CPU。
修复
动画改为按需启动:
`@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (getVisibility() == VISIBLE) {
startAnimation();
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
stopAnimation();
}
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (visibility == VISIBLE) {
startAnimation();
} else {
stopAnimation();
}
}
`
验证
修复后 GPU 柱状图基本都在绿线以下,滑动流畅。
教训
Visibility GONE 不代表不消耗资源,生命周期要管好
自定义 View 的 onAttachedToWindow / onDetachedFromWindow 要重视
性能问题先用 GPU 渲染模式看,别凭感觉猜
代码就不贴了,都是业务里的东西,脱敏麻烦。主要是记录排查思路,如果也有人遇到类似的莫名其妙卡顿,可以往这个方向查查。
