Android Adapter中如何判断ViewHolder是否初始化,避免重复设值?
兄弟,先得明确一点:ListView/RecyclerView的ViewHolder复用机制,核心就是滚动时复用旧视图,然后重新绑定当前位置的数据——所以你现在每次滚动都执行holder.textView.setText(deal.getPrice())其实是正常且必要的,不然复用的ViewHolder会显示上一个位置的旧数据。
但如果你的需求是把「只需要初始化一次的操作」(比如UI控件的样式、固定事件)和「每次都要更新的动态数据绑定」分开,或者确实有部分数据绑定后就不会再变化,那可以按下面两种方式处理:
方式一:区分「视图初始化」和「数据绑定」
把只需要执行一次的操作(比如控件的字体、背景、固定点击事件)放在convertView == null的分支里,而动态数据绑定(比如设置文本、图片)放在外面每次执行:
public View getView(final int position, View convertView, ViewGroup parent) { final ViewHolder holder; if (convertView == null) { // 初始化视图,只执行一次 convertView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.your_item_layout, parent, false); holder = new ViewHolder(); holder.textView = convertView.findViewById(R.id.text_view); // 这里放只需要初始化一次的逻辑:比如设置字体颜色、固定点击事件 holder.textView.setTextColor(Color.parseColor("#333333")); holder.textView.setOnClickListener(v -> { // 固定的点击逻辑,比如跳转详情页 int clickedPosition = (int) v.getTag(); // 处理点击事件 }); convertView.setTag(holder); } else { // 复用已有的ViewHolder holder = (ViewHolder) convertView.getTag(); } Deal deal = dealsArr.get(position); // 动态数据绑定,每次滚动都要执行(因为当前位置的deal变了) holder.textView.setText(deal.getPrice()); holder.textView.setTag(position); // 给点击事件传递当前位置 changePrice(deal, true); return convertView; } // ViewHolder定义 static class ViewHolder { TextView textView; }
方式二:给ViewHolder加标记,判断是否已绑定当前数据
如果某些数据绑定后就不会再变化(比如deal的价格不会更新),可以给ViewHolder加一个标记(比如绑定的deal的ID),判断当前要显示的deal是否已经绑定过,避免重复操作:
// 给ViewHolder增加标记字段 static class ViewHolder { TextView textView; String boundDealId; // 保存已经绑定的deal的唯一ID } public View getView(final int position, View convertView, ViewGroup parent) { final ViewHolder holder; if (convertView == null) { convertView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.your_item_layout, parent, false); holder = new ViewHolder(); holder.textView = convertView.findViewById(R.id.text_view); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } Deal deal = dealsArr.get(position); // 判断当前deal是否已经绑定过,未绑定才执行数据设置 if (holder.boundDealId == null || !holder.boundDealId.equals(deal.getId())) { holder.textView.setText(deal.getPrice()); holder.boundDealId = deal.getId(); changePrice(deal, true); } return convertView; }
注意事项:
这种方式要小心,如果后续deal的数据会更新(比如价格变化),那即使ID相同,也需要重新绑定数据。这时候你需要在数据更新时调用notifyDataSetChanged()或者notifyItemChanged(position),或者直接去掉判断逻辑,保证数据能及时更新。
最后再提醒一句:如果是担心重复设置数据的性能问题,建议优化数据绑定的逻辑(比如缓存计算后的价格字符串、避免每次都调用耗时方法),而不是跳过绑定——跳过绑定很容易导致显示旧数据的bug,违背ViewHolder复用的设计初衷。
内容的提问来源于stack exchange,提问作者Igor F.

