SearchView过滤RecyclerView时列表未即时更新,需滚动后才生效的问题求助
解决RecyclerView过滤后不即时更新的问题
嘿,我一眼就瞅出你踩的坑啦——你的LocationAdapter里的publishResults方法是空的!这就是为啥过滤后列表不会即时刷新,非得滚动才生效的核心原因。
问题分析
RecyclerView的Filter工作流程是:
performFiltering在后台线程处理过滤逻辑,返回结果publishResults在主线程接收结果,更新适配器数据并通知UI刷新
你现在只在performFiltering里处理了过滤数据,但完全没在publishResults里把结果同步到适配器,也没通知RecyclerView刷新。那些留在屏幕顶部的旧item,只有当它们被滚动出屏幕、ViewHolder被回收复用的时候,才会重新绑定新的过滤后数据,所以你才会看到“滚动后才消失”的现象。
修复方案
只需要两步就能搞定:
- 完善
publishResults方法,把过滤结果赋值给locationsFiltered,然后调用notifyDataSetChanged()触发UI刷新 - 初始化
locationsFiltered时创建原列表的副本,避免和原数据共用同一个引用(防止原数据被意外修改)
修改后的Adapter代码
class LocationAdapter( private var locations: ArrayList<Costcenter>, private val onLocationClick: (location: Costcenter) -> Unit ) : RecyclerView.Adapter<LocationAdapter.LocationViewHolder>(), Filterable { // 初始化时创建原列表的副本,避免引用同一对象 var locationsFiltered = ArrayList(locations) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LocationViewHolder { val view = LayoutInflater .from(parent.context) .inflate(R.layout.location_row, parent, false) return LocationViewHolder(view) } override fun getItemCount(): Int = locationsFiltered.size override fun onBindViewHolder(holder: LocationViewHolder, position: Int) { holder.bind(locationsFiltered[position]) } inner class LocationViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private val title: TextView = itemView.findViewById(R.id.txtCostCenter) private val desc: TextView = itemView.findViewById(R.id.txtCostCenterDescription) fun bind(loc: Costcenter) { title.text = loc.goederenontvanger desc.text = loc.goederenontvanger_omschrijving itemView.setOnClickListener { onLocationClick.invoke(loc) } } } override fun getFilter(): Filter { return object : Filter() { override fun performFiltering(constraint: CharSequence?): FilterResults { val charSearch = constraint.toString() val resultList = if (charSearch.isEmpty()) { // 空搜索时返回原列表的副本 ArrayList(locations) } else { val tempList = ArrayList<Costcenter>() for (row in locations) { if (row.goederenontvanger.toLowerCase() .contains(charSearch.toLowerCase()) || row.goederenontvanger_omschrijving.toLowerCase() .contains(charSearch.toLowerCase()) ) { tempList.add(row) } } tempList } val filterResults = FilterResults() filterResults.values = resultList return filterResults } override fun publishResults(constraint: CharSequence?, results: FilterResults?) { // 把过滤结果赋值给适配器的数据源 locationsFiltered = results?.values as ArrayList<Costcenter> // 通知RecyclerView刷新所有item notifyDataSetChanged() } } } }
额外优化提示
如果你的数据量后续变大,notifyDataSetChanged()会刷新整个列表,有点不够高效。这时候可以用DiffUtil来计算新旧数据的差异,只刷新变化的item,但对于3000条数据来说,当前的修复已经完全够用啦。
内容的提问来源于stack exchange,提问作者Cevdam
相关产品推荐
相关产品推荐

