You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SearchView过滤RecyclerView时列表未即时更新,需滚动后才生效的问题求助

解决RecyclerView过滤后不即时更新的问题

嘿,我一眼就瞅出你踩的坑啦——你的LocationAdapter里的publishResults方法是空的!这就是为啥过滤后列表不会即时刷新,非得滚动才生效的核心原因。

问题分析

RecyclerView的Filter工作流程是:

  1. performFiltering在后台线程处理过滤逻辑,返回结果
  2. publishResults在主线程接收结果,更新适配器数据并通知UI刷新

你现在只在performFiltering里处理了过滤数据,但完全没在publishResults里把结果同步到适配器,也没通知RecyclerView刷新。那些留在屏幕顶部的旧item,只有当它们被滚动出屏幕、ViewHolder被回收复用的时候,才会重新绑定新的过滤后数据,所以你才会看到“滚动后才消失”的现象。

修复方案

只需要两步就能搞定:

  1. 完善publishResults方法,把过滤结果赋值给locationsFiltered,然后调用notifyDataSetChanged()触发UI刷新
  2. 初始化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 06:57:37