安卓笔记应用SearchView搜索时Adapter数据消失问题排查
问题分析与解决方案
嘿,我仔细看了你的代码,发现搜索后列表消失的问题根源很明确——你的Adapter里的数据源副本没有和实时数据同步,具体来说是这几点:
问题出在哪?
arrayListCopy没有同步更新:你在Adapter构造时把传入的list复制到了arrayListCopy,但之后用户通过弹窗添加新笔记时,新笔记只被加到了MainActivity的list和Adapter的arrayList里,完全没同步到arrayListCopy。当执行搜索时,你清空了arrayList,然后从arrayListCopy里捞数据,但这个副本里根本没有新添加的笔记,自然搜不到内容,甚至会因为副本为空导致整个列表消失。- 删除操作也没同步副本:用户长按删除笔记时,只删了
arrayList里的项,arrayListCopy里的旧数据还在,这会导致后续搜索时出现已经被删除的笔记。 - MainActivity的通知方法错误:你添加笔记后调用
notifyItemChanged(list.size()),这是更新已有项的方法,应该用notifyItemInserted(list.size() - 1)来通知RecyclerView插入了新项。
怎么修改?
我们可以重构Adapter的数据源结构,让原始数据和显示数据分离,同时把数据操作封装到Adapter里,保证同步:
第一步:修改NotesAdapter代码
public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.NotesHolder> { private ArrayList<Notes> originalList; // 保存所有原始笔记,作为唯一真实数据源 private ArrayList<Notes> filteredList; // 保存当前要显示的笔记(筛选后或全部) Context c; NotesAdapter(Context context, ArrayList<Notes> list){ this.c = context; this.originalList = new ArrayList<>(list); // 初始化原始数据 this.filteredList = new ArrayList<>(list); // 初始化显示列表为全部数据 } // 封装添加笔记的方法,同步更新两个列表 public void addNote(Notes note) { originalList.add(note); filteredList.add(note); notifyItemInserted(filteredList.size() - 1); // 正确通知插入新项 } // 封装删除笔记的方法,同步更新两个列表 public void removeNote(int position) { Notes noteToRemove = filteredList.get(position); originalList.remove(noteToRemove); filteredList.remove(position); notifyItemRemoved(position); } public class NotesHolder extends RecyclerView.ViewHolder { TextView textView; public NotesHolder(View itemView) { super(itemView); textView = itemView.findViewById(R.id.tv); } } @Override public NotesAdapter.NotesHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new NotesHolder(LayoutInflater.from(c).inflate(R.layout.item_row, parent, false)); } @Override public void onBindViewHolder(final NotesAdapter.NotesHolder holder, final int position) { final Notes currentNote = filteredList.get(position); // 从显示列表取数据 holder.textView.setText(currentNote.getTitle()); holder.textView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { removeNote(holder.getAdapterPosition()); // 调用封装的删除方法 return true; } }); holder.textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(c, AnotherActivity.class); intent.putExtra("NAME", currentNote.getDescription()); c.startActivity(intent); } }); } @Override public int getItemCount() { return filteredList.size(); // 返回显示列表的长度 } public void filter(String text){ filteredList.clear(); if(TextUtils.isEmpty(text)){ filteredList.addAll(originalList); // 空搜索时显示全部原始数据 } else{ text = text.toLowerCase(); for(Notes note : originalList){ if(note.getTitle().toLowerCase().contains(text)){ filteredList.add(note); } } } notifyDataSetChanged(); } }
第二步:修改MainActivity中的添加笔记逻辑
把原来直接操作list的代码改成调用Adapter的addNote方法:
.setPositiveButton("add", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { Notes newNote = new Notes(title.getText().toString(), description.getText().toString(), false); notesAdapter.addNote(newNote); // 交给Adapter处理添加和通知 // 原来的list.add和notifyItemChanged都可以删掉了 } })
为什么这样改?
- 数据源同步:
originalList始终保存着最新的所有笔记,添加/删除操作都会同步更新它,搜索筛选时基于这个最新的数据源,不会再出现遗漏或错误。 - 职责分离:把数据操作封装在Adapter里,避免了Activity和Adapter之间的数据源不一致问题,代码结构更清晰。
- 正确的RecyclerView通知:用
notifyItemInserted和notifyItemRemoved代替错误的notifyItemChanged,RecyclerView的动画也能正常工作。
内容的提问来源于stack exchange,提问作者Tanishq Saluja
相关产品推荐
相关产品推荐

