ViewPager中RecyclerView结合SearchView筛选显示内容异常问题
问题描述
在包含两个Fragment的ViewPager中,Fragment2内通过SearchView对RecyclerView进行数据筛选时出现异常:输入筛选内容后,RecyclerView显示的条目内容与预期不符,但点击条目弹出的Toast却能正确显示对应条目的名称。
RecyclerView适配器代码(带筛选功能)
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyviewHolder> implements Filterable { ListItemsBinding itembind; Context co; List<Items> mylist; List<Items> copy; public CustomAdapter(List<Items> mylist, Context co) { this.mylist = mylist; copy=new ArrayList<>(mylist); this.co = co; } @NonNull @Override public CustomAdapter.MyviewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(co); itembind= ListItemsBinding.inflate(inflater,parent,false); return new MyviewHolder(itembind); } @Override public void onBindViewHolder(@NonNull CustomAdapter.MyviewHolder holder, int position) { Items item = mylist.get(position); itembind.text.setText(item.getName()); } @Override public int getItemCount() { return mylist.size(); } @Override public int getItemViewType(int position) { return position; } @Override public Filter getFilter() { return exampleFilter; } private final Filter exampleFilter = new Filter() { @Override protected FilterResults performFiltering(CharSequence constraint) { List<Items> filteredList = new ArrayList<>(); if (constraint == null || constraint.length() == 0) { filteredList.addAll(copy); } else { String filterPattern = constraint.toString().toLowerCase().trim(); for (Items item : copy) { if (item.getName().toLowerCase().contains(filterPattern)) { filteredList.add(item); } } } FilterResults results = new FilterResults(); results.values = filteredList; return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { mylist.clear(); mylist.addAll((List) results.values); notifyDataSetChanged(); } }; public class MyviewHolder extends RecyclerView.ViewHolder { public MyviewHolder(ListItemsBinding itembind) { super(itembind.getRoot()); itembind.const1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(co,""+mylist.get(getAdapterPosition()).getName(),Toast.LENGTH_SHORT).show(); } }); } } }
Fragment2代码(已实现onCreateOptionsMenu)
public class Fragment2 extends Fragment { CustomAdapter adaptive; List<Items> mylist; Fragment2Binding filesbinding; Context context; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { filesbinding= FragmentVoiceRecordFilesBinding.inflate(inflater,container,false); context = getContext(); return filesbinding.getRoot(); } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); setdata(); recycle(); } public void recycle() { filesbinding.recycle.setHasFixedSize(true); RecyclerView.LayoutManager layout = new LinearLayoutManager(context); filesbinding.recycle.setLayoutManager(layout); filesbinding.recycle.scheduleLayoutAnimation(); adaptive= new CustomAdapter(mylist,context); filesbinding.recycle.setAdapter(adaptive); } public void setdata() { mylist=new ArrayList<>(); mylist.add(new Items("1")); mylist.add(new Items("2")); mylist.add(new Items("3")); mylist.add(new Items("4")); } @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { inflater.inflate(R.menu.search_menu, menu); MenuItem searchItem = menu.findItem(R.id.actionSearch); SearchView searchView = (SearchView) searchItem.getActionView(); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { return false; } @Override public boolean onQueryTextChange(String newText) { adaptive.getFilter().filter(newText); return false; } }); super.onCreateOptionsMenu(menu, inflater); } }
searchmenu.xml代码
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/actionSearch" android:icon="@drawable/ic_baseline_search_24" android:title="Search" app:actionViewClass="androidx.appcompat.widget.SearchView" app:showAsAction="always|collapseActionView" /> </menu>
问题原因及修复方案
问题根源
适配器中的ListItemsBinding itembind是类成员变量,而非每个ViewHolder独立持有。当RecyclerView复用ViewHolder时,所有条目都会复用同一个binding实例,导致最后一次调用onBindViewHolder时设置的文本会覆盖之前所有条目的显示内容。而点击事件中是通过getAdapterPosition()从数据源mylist获取正确数据,所以Toast显示正常。
修复步骤
- 将适配器中的
ListItemsBinding itembind改为onCreateViewHolder方法内的局部变量,不再作为类成员。 - 在
MyviewHolder中持有自己的ListItemsBinding实例,确保每个条目有独立的绑定对象。 - 在
onBindViewHolder中通过holder的binding来设置文本内容。
修改后的适配器代码:
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyviewHolder> implements Filterable { Context co; List<Items> mylist; List<Items> copy; public CustomAdapter(List<Items> mylist, Context co) { this.mylist = mylist; copy=new ArrayList<>(mylist); this.co = co; } @NonNull @Override public CustomAdapter.MyviewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(co); // 改为局部变量,每个ViewHolder创建独立的binding ListItemsBinding itembind= ListItemsBinding.inflate(inflater,parent,false); return new MyviewHolder(itembind); } @Override public void onBindViewHolder(@NonNull CustomAdapter.MyviewHolder holder, int position) { Items item = mylist.get(position); // 使用当前holder的binding设置文本 holder.itembind.text.setText(item.getName()); } @Override public int getItemCount() { return mylist.size(); } @Override public int getItemViewType(int position) { return position; } @Override public Filter getFilter() { return exampleFilter; } private final Filter exampleFilter = new Filter() { @Override protected FilterResults performFiltering(CharSequence constraint) { List<Items> filteredList = new ArrayList<>(); if (constraint == null || constraint.length() == 0) { filteredList.addAll(copy); } else { String filterPattern = constraint.toString().toLowerCase().trim(); for (Items item : copy) { if (item.getName().toLowerCase().contains(filterPattern)) { filteredList.add(item); } } } FilterResults results = new FilterResults(); results.values = filteredList; return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { mylist.clear(); mylist.addAll((List) results.values); notifyDataSetChanged(); } }; public class MyviewHolder extends RecyclerView.ViewHolder { // ViewHolder持有自己的binding实例 ListItemsBinding itembind; public MyviewHolder(ListItemsBinding itembind) { super(itembind.getRoot()); this.itembind = itembind; itembind.const1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(co,""+mylist.get(getAdapterPosition()).getName(),Toast.LENGTH_SHORT).show(); } }); } } }
内容的提问来源于stack exchange,提问作者A.G
相关产品推荐
相关产品推荐

