切换明暗模式时Android ListView出现重复项问题求助
Android笔记应用明暗模式切换后ListView出现重复项的解决方案
问题根源
你的ListView出现重复项的核心原因是自定义Adapter的getView方法中,复用已有的Item View时,没有清空ChipGroup中的旧标签(Chip)。每次切换主题触发视图刷新后,getView会复用之前的View,而旧的Chip仍然保留,新的Chip又被添加进去,导致标签重复。同时,getView中存在一些不必要的重复操作,也会加重问题。
修复步骤及代码修改
1. 优化View复用与Holder逻辑
- 仅在创建新View时初始化NoteHolder,复用View时直接从Tag中获取;
- 将CardView等固定View的初始化移到View创建阶段,避免每次findViewById浪费性能;
2. 强制清空ChipGroup再加载新标签
无论当前View是新创建还是复用的,在添加新Chip之前,必须清空ChipGroup的所有子View,确保每个Item只显示当前笔记的标签。
修改后的getView方法代码
public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; NoteHolder holder; Note n = noteList.get(position); Set<String> folders = n.getFolders(); Set<String> foldersForChips = new HashSet<>(folders); foldersForChips.remove("Notes"); foldersForChips.remove("All Notes"); if (v == null) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = inflater.inflate(R.layout.row_layout, parent, false); holder = new NoteHolder(); // 一次性初始化所有View到Holder中 holder.foldersChipGroup = v.findViewById(R.id.labels_of_note); holder.foldersChipGroup.setChipSpacingHorizontal(2); holder.foldersChipGroup.setClickable(false); holder.foldersChipGroup.setFocusable(false); holder.titleView = v.findViewById(R.id.title); holder.contentView = v.findViewById(R.id.content); holder.cardView = v.findViewById(R.id.cardView); v.setTag(holder); } else { holder = (NoteHolder) v.getTag(); } // 关键操作:清空旧标签,避免复用重复 holder.foldersChipGroup.removeAllViews(); // 添加当前笔记的标签 for (String folder : foldersForChips) { Chip folderChip = new Chip(context); folderChip.setText(folder); folderChip.setTextSize(8); folderChip.setEnsureMinTouchTargetSize(false); folderChip.setHeight(40); folderChip.setChipMinHeight(10); folderChip.setBackgroundColor(Color.TRANSPARENT); folderChip.setChipBackgroundColor(null); ChipDrawable chipFolderDrawable = ChipDrawable.createFromAttributes(context, null, 0, R.style.Widget_App_Chip); folderChip.setChipDrawable(chipFolderDrawable); holder.foldersChipGroup.addView(folderChip); } // 重置标题和内容的可见性,避免复用旧状态 holder.titleView.setVisibility(View.GONE); holder.contentView.setVisibility(View.GONE); // 处理标题和内容的显示逻辑 if (n.getTitle() == null || n.getTitle().trim().isEmpty()) { holder.contentView.setVisibility(View.VISIBLE); holder.contentView.setText(n.getContent()); holder.contentView.setPadding(20, 0, 20, 0); } else if (n.getContent() == null || n.getContent().trim().isEmpty()) { holder.titleView.setVisibility(View.VISIBLE); holder.titleView.setText(n.getTitle()); holder.titleView.setPadding(20, 0, 20, 0); } else { holder.titleView.setVisibility(View.VISIBLE); holder.titleView.setText(n.getTitle()); holder.titleView.setPadding(20, 0, 20, 0); holder.contentView.setVisibility(View.VISIBLE); holder.contentView.setText(n.getContent()); holder.contentView.setPadding(20, 0, 20, 0); } // 设置卡片背景色 if (getItem(position).getBackgroundColor() != null) { holder.cardView.setCardBackgroundColor(Color.parseColor(getItem(position).getBackgroundColor())); } return v; }
3. 简化主题切换代码
调用AppCompatDelegate.setDefaultNightMode后,系统会自动重建当前Activity以应用新主题,因此不需要手动调用视图刷新方法,可简化代码:
FloatingActionButton fabLight = findViewById(R.id.light); fabLight.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); themeChange.setVisibility(View.VISIBLE); SharedPreferences settingsPreferences = getApplicationContext().getSharedPreferences("com.example.settings", Context.MODE_PRIVATE); settingsPreferences.edit().putInt("Mode", AppCompatDelegate.MODE_NIGHT_NO).apply(); } });
额外建议
- 字符串判空时使用
trim().isEmpty(),避免空格导致的误判; - 初始化View时使用
inflater.inflate(R.layout.row_layout, parent, false)而非传入null,确保布局参数正确应用; - 建议使用RecyclerView替代ListView,其复用机制更完善,也更适配现代Android开发需求。
内容的提问来源于stack exchange,提问作者Weronika Materkowska
相关产品推荐
相关产品推荐

