Android ListView条目显示重复、顺序异常问题求助
Android ListView 更新后显示重复数据问题
问题现象
原本ListView显示2个条目:
- Item 1(position 0)
- Item 2(position 1)
重新加载数据源后(数据源仍为这两个条目),ListView显示异常:
- Item 2(position 0)
- Item 2(position 1)
但点击position 0能获取Item1的正确数据,点击position1能获取Item2的正确数据,仅显示内容重复。
相关代码
Fragment 列表初始化与更新代码
public class FishTankFragment extends DeviceFragment { ... private final List<FishTankStatus.Schedule> schedulesList = new ArrayList<>(); private ScheduleAdapter scheduleAdapter; ... @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ... scheduleAdapter = new ScheduleAdapter(view.getContext(), schedulesList); screenBinding.lvSchedules.setAdapter(scheduleAdapter); screenBinding.lvSchedules.setOnItemClickListener((parent, view1, position, id) -> { new ScheduleItemClickListener(this.getContext(), schedulesList.get(position), position); }); ... } @Override public <T> void onResponse(T responseObject) { ... schedulesList.clear(); schedulesList.addAll(data.getSchedules()); scheduleAdapter.notifyDataSetChanged(); ... }
Adapter 代码
public class ScheduleAdapter extends BaseAdapter { private ScheduleItemBinding itemBinding; private final List<FishTankStatus.Schedule> schedules; private final Context context; public ScheduleAdapter(@NonNull Context context, @NonNull List<FishTankStatus.Schedule> objects) { this.context = context; schedules = objects; } @Override public int getCount() { return schedules.size(); } @Override public FishTankStatus.Schedule getItem(int position) { return schedules.get(position); } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View view, ViewGroup parent) { if (view == null) { itemBinding = ScheduleItemBinding.inflate(LayoutInflater.from(context)); view = itemBinding.getRoot(); } if (!schedules.isEmpty()) { String start = StringUtils.printTime(schedules.get(position).getStart()); String end = StringUtils.printTime(schedules.get(position).getEnd()); itemBinding.tvScheduleStart.setText(start); itemBinding.tvScheduleEnd.setText(end); FishTankStatus.Schedule schedule = schedules.get(position); for (String device : schedule.getDevices()) { switch (device) { case "something": itemBinding.ivYellowlightIcon.setVisibility(View.VISIBLE); break; case "something 1": itemBinding.ivBluelightIcon.setVisibility(View.VISIBLE); break; case "something 2": itemBinding.ivAirIcon.setVisibility(View.VISIBLE); } } if (schedules.get(position).getActive()) { ColorStateList white = ColorStateList.valueOf( view.getResources().getColor(R.color.white, view.getContext().getTheme())); itemBinding.lySchedule.setBackground(ResourcesCompat.getDrawable(view.getResources(), R.drawable.rectangle_p_light_8, view.getContext().getTheme())); ... } } return view; } }
已确认信息
- 执行
schedulesList.clear()后集合为空,addAll后Fragment和Adapter中的集合数据均正确 - 尝试在Adapter中使用独立集合执行clear和addAll操作,问题依旧
- ListView在父ConstraintLayout中宽高设为match_parent,父布局宽为0dp、高为match_parent
问题原因与解决方案
核心问题
- Binding实例复用错误:
itemBinding是Adapter的成员变量,复用View时,新position的Binding会覆盖旧引用,导致所有复用View都使用最后一次创建的Binding实例,显示重复内容。 - 控件状态未重置:设置图标可见性、背景等状态时,未处理反向场景(如条目不含某设备时,未将对应图标设为GONE),导致旧条目状态残留。
修复后的Adapter实现
@Override public View getView(int position, View view, ViewGroup parent) { ScheduleItemBinding binding; // 用View的Tag存储Binding,避免成员变量覆盖问题 if (view == null) { binding = ScheduleItemBinding.inflate(LayoutInflater.from(context), parent, false); view = binding.getRoot(); view.setTag(binding); } else { binding = (ScheduleItemBinding) view.getTag(); } if (!schedules.isEmpty()) { FishTankStatus.Schedule schedule = schedules.get(position); String start = StringUtils.printTime(schedule.getStart()); String end = StringUtils.printTime(schedule.getEnd()); binding.tvScheduleStart.setText(start); binding.tvScheduleEnd.setText(end); // 先重置所有图标状态,避免复用旧数据 binding.ivYellowlightIcon.setVisibility(View.GONE); binding.ivBluelightIcon.setVisibility(View.GONE); binding.ivAirIcon.setVisibility(View.GONE); for (String device : schedule.getDevices()) { switch (device) { case "something": binding.ivYellowlightIcon.setVisibility(View.VISIBLE); break; case "something 1": binding.ivBluelightIcon.setVisibility(View.VISIBLE); break; case "something 2": binding.ivAirIcon.setVisibility(View.VISIBLE); break; } } // 处理激活/非激活状态,必须覆盖两种场景 if (schedule.getActive()) { ColorStateList white = ColorStateList.valueOf( view.getResources().getColor(R.color.white, view.getContext().getTheme())); binding.lySchedule.setBackground(ResourcesCompat.getDrawable(view.getResources(), R.drawable.rectangle_p_light_8, view.getContext().getTheme())); // 补充激活状态的其他样式设置 } else { // 恢复非激活状态的默认样式 binding.lySchedule.setBackground(ResourcesCompat.getDrawable(view.getResources(), R.drawable.your_default_background, view.getContext().getTheme())); // 补充非激活状态的其他样式设置 } } return view; }
内容的提问来源于stack exchange,提问作者Juro_222
相关产品推荐
相关产品推荐

