RecyclerView中NotifyDataSetChanged不生效,搜索筛选结果无法显示
SearchBar筛选后RecyclerView不显示过滤结果的解决方法
尝试用SearchBar对ArrayList进行筛选并将结果展示在RecyclerView中,日志显示数据已成功过滤,但过滤后的结果并未在RecyclerView中显示,求解决。
Activity代码
class RegisterActivity_7_Taste : AppCompatActivity(), OnTasteClickListener { private lateinit var binding : LayoutRegisterTasteBinding var taste_list = ArrayList<String>() private lateinit var adapter : RecyclerViewAdapter_Taste var check_taste = ArrayList<String>() val database = FirebaseDatabase.getInstance("url") val ref = database.getReference("path") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = LayoutRegisterTasteBinding.inflate(layoutInflater) setContentView(binding.root) val taste_string = getSharedPreferences("data_booster", 0).getString("taste", "failed") taste_list = taste_string!!.split(",").distinct() as ArrayList<String> val editor = getSharedPreferences("data_cloud", 0).edit() binding.tasteSearch.setOnQueryTextListener(searchViewTextListener) binding.tasteSelect.layoutManager = LinearLayoutManager(this) adapter = RecyclerViewAdapter_Taste(taste_list, this) binding.tasteSelect.setAdapter(adapter) } var searchViewTextListener: SearchView.OnQueryTextListener = object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(s: String): Boolean { return false } override fun onQueryTextChange(s: String): Boolean { adapter.filter.filter(s) Log.d("RegisterActivity_8_Taste", "SearchView Text is Changed : $s") return false } } }
原Adapter代码
class RecyclerViewAdapter_Taste(private val taste_list : ArrayList<String>, private val listener : OnTasteClickListener) : RecyclerView.Adapter<RecyclerViewAdapter_Taste.MyViewHolder>(), Filterable { inner class MyViewHolder(binding : FragmentRegisterTasteAdapterBinding) : RecyclerView.ViewHolder(binding.root) { val btn = binding.btn val root = binding.root } var TAG = "TasteRecyclerViewAdapter" var filteredTaste = ArrayList<String>() var itemFilter = ItemFilter() init { filteredTaste.addAll(taste_list) } var check : Boolean = false override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val binding : FragmentRegisterTasteAdapterBinding = FragmentRegisterTasteAdapterBinding.inflate(LayoutInflater.from(parent.context), parent, false) return MyViewHolder(binding) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val taste_name = taste_list[position].toString() holder.btn.text = taste_name holder.btn.setOnClickListener { if(check == false) { holder.btn.setBackgroundResource(R.drawable.btn_main_color) listener.onTasteClickAdd(taste_name) check = true } else { holder.btn.setBackgroundResource(R.drawable.btn_sub_color_light) listener.onTasteClickRemove(taste_name) check = false } } } override fun getItemCount(): Int { return taste_list.size } override fun getFilter() : Filter { return itemFilter } inner class ItemFilter : Filter() { override fun performFiltering(p: CharSequence?): FilterResults { val filterString = p.toString() val results = FilterResults() Log.d(TAG, "charSequence : $p") val filteredList : ArrayList<String> = ArrayList<String>() if(filterString.trim{it<= ' '}.isEmpty()) { results.values = taste_list results.count = taste_list.size } else { for (taste in taste_list) { if (taste.contains(filterString)) { filteredList.add(taste) } } results.values = filteredList results.count = filteredList.size } return results } @SuppressLint("NotifyDataSetChanged") override fun publishResults(p0: CharSequence?, p1: FilterResults) { filteredTaste.clear() filteredTaste.addAll(p1.values as ArrayList<String>) notifyDataSetChanged() } } }
问题原因及修复方案
核心问题:数据源不匹配
Adapter中虽维护了filteredTaste存储过滤后的结果,但onBindViewHolder和getItemCount仍在使用原始的taste_list,导致RecyclerView始终展示原始数据,而非过滤后的结果。
额外问题:选中状态全局共享
全局变量check会导致所有列表项的选中状态共用同一个值,点击任意一个按钮,所有按钮的状态都会同步变化,不符合需求。
修改后的Adapter代码
class RecyclerViewAdapter_Taste(private val taste_list : ArrayList<String>, private val listener : OnTasteClickListener) : RecyclerView.Adapter<RecyclerViewAdapter_Taste.MyViewHolder>(), Filterable { inner class MyViewHolder(binding : FragmentRegisterTasteAdapterBinding) : RecyclerView.ViewHolder(binding.root) { val btn = binding.btn val root = binding.root // 每个item独立维护选中状态 var isChecked = false } var TAG = "TasteRecyclerViewAdapter" var filteredTaste = ArrayList<String>() var itemFilter = ItemFilter() init { filteredTaste.addAll(taste_list) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val binding : FragmentRegisterTasteAdapterBinding = FragmentRegisterTasteAdapterBinding.inflate(LayoutInflater.from(parent.context), parent, false) return MyViewHolder(binding) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { // 改用过滤后的数据源 val taste_name = filteredTaste[position].toString() holder.btn.text = taste_name // 恢复item状态,防止滚动时状态错乱 holder.btn.setBackgroundResource(if (holder.isChecked) R.drawable.btn_main_color else R.drawable.btn_sub_color_light) holder.btn.setOnClickListener { holder.isChecked = !holder.isChecked if(holder.isChecked) { holder.btn.setBackgroundResource(R.drawable.btn_main_color) listener.onTasteClickAdd(taste_name) } else { holder.btn.setBackgroundResource(R.drawable.btn_sub_color_light) listener.onTasteClickRemove(taste_name) } } } override fun getItemCount(): Int { // 返回过滤后的列表长度 return filteredTaste.size } override fun getFilter() : Filter { return itemFilter } inner class ItemFilter : Filter() { override fun performFiltering(p: CharSequence?): FilterResults { val filterString = p.toString().lowercase() // 不区分大小写搜索(可选) val results = FilterResults() Log.d(TAG, "charSequence : $p") val filteredList : ArrayList<String> = ArrayList<String>() if(filterString.trim().isEmpty()) { filteredList.addAll(taste_list) } else { for (taste in taste_list) { // 不区分大小写匹配 if (taste.lowercase().contains(filterString)) { filteredList.add(taste) } } } results.values = filteredList results.count = filteredList.size return results } @SuppressLint("NotifyDataSetChanged") override fun publishResults(p0: CharSequence?, p1: FilterResults) { filteredTaste.clear() filteredTaste.addAll(p1.values as ArrayList<String>) notifyDataSetChanged() } } }
修改说明
- 数据源切换:将
onBindViewHolder中的taste_list替换为filteredTaste,getItemCount返回filteredTaste.size,确保RecyclerView展示过滤后的结果。 - 选中状态独立:将选中状态变量移到
MyViewHolder内部,每个列表项单独维护自己的选中状态,避免全局状态污染。 - 状态恢复:在
onBindViewHolder中根据isChecked恢复按钮背景,防止RecyclerView滚动时item状态错乱。 - 可选优化:将搜索字符串和匹配字符串转为小写,实现不区分大小写的搜索,提升用户体验。
内容的提问来源于stack exchange,提问作者jungdennis
相关产品推荐
相关产品推荐

