无条件布局填充问题:如何使用ViewHolder模式优化滚动性能?
解决列表滚动卡顿:ViewHolder模式实战指南
嘿,作为刚入门的开发者,遇到列表滚动卡顿太正常啦!ViewHolder模式正是解决这个问题的核心方案,我来一步步给你拆解清楚怎么改~
为啥会卡顿?
每次列表滚动时,getView()方法会被频繁调用。如果每次都在方法里调用findViewById()去查找控件,这是个非常耗时的操作——系统得反复遍历布局树找控件,列表项越多、布局越复杂,卡顿就越明显。ViewHolder的本质就是把这些控件缓存起来,避免重复查找,从而提升滚动流畅度。
怎么用ViewHolder修复?
我直接给你对比新旧写法,一看就懂:
1. 先看你的原始(卡顿)写法
@Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false); } // 每次滚动都重新查找控件,耗时! TextView titleTv = convertView.findViewById(R.id.title_tv); ImageView iconIv = convertView.findViewById(R.id.icon_iv); // 设置数据 titleTv.setText(dataList.get(position).getTitle()); iconIv.setImageResource(dataList.get(position).getIconRes()); return convertView; }
2. 改成ViewHolder模式的写法
第一步:定义ViewHolder静态内部类
把列表项里所有需要操作的控件都放到这个类里,作为成员变量:
// 必须是静态内部类,避免内存泄漏 static class ViewHolder { TextView titleTv; ImageView iconIv; // 如果还有其他控件,比如Button、CheckBox,都加在这里 }
第二步:修改getView()方法,复用ViewHolder
@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; // 第一次加载布局时,初始化ViewHolder并绑定控件 if (convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false); holder = new ViewHolder(); // 只在第一次查找控件,之后再也不用找了! holder.titleTv = convertView.findViewById(R.id.title_tv); holder.iconIv = convertView.findViewById(R.id.icon_iv); // 把ViewHolder存到convertView的Tag里,方便后续取出 convertView.setTag(holder); } else { // 滚动复用布局时,直接从Tag里取出缓存的ViewHolder holder = (ViewHolder) convertView.getTag(); } // 通过ViewHolder直接操作控件,设置数据 holder.titleTv.setText(dataList.get(position).getTitle()); holder.iconIv.setImageResource(dataList.get(position).getIconRes()); return convertView; }
额外优化小Tips
- 图片加载别用同步加载:如果你的列表项里有网络图片,一定要用异步加载库,别在getView里直接加载,不然照样卡顿。
- 避免在getView里做耗时操作:比如解析JSON、计算复杂数据,这些都要提前在子线程处理好,把结果存到数据源里,getView只负责显示数据。
- 布局尽量扁平化:列表项的布局层级越少越好,减少系统绘制的压力,也能间接提升流畅度。
这样改完之后,你再试试滚动列表,应该就丝滑多啦!
内容的提问来源于stack exchange,提问作者niel
相关产品推荐
相关产品推荐

