Fragment中集成SearchView与RecyclerView后搜索无结果如何排查解决
搜索无结果问题的逐点修复
以下为代码中存在的逻辑错误,按优先级修复即可实现正常的搜索联动:
1. 空引用异常:类成员adapter从未被赋值
- SearchFragment中声明了
lateinit var adapter: AdapterSearch,但全流程代码从未将RecyclerView绑定的Adapter实例赋值给该变量 - 当SearchView输入触发回调执行
adapter.filter.filter(newText)时,直接抛出UninitializedPropertyAccessException,过滤逻辑完全不会执行 - 修复方式:在addList()初始化Adapter时,将实例赋值给类成员:
// 原错误代码 recyclerView?.adapter= AdapterSearch(s,object: AdapterSearch.OnClickListener{...}) // 修改为 adapter = AdapterSearch(s, object: AdapterSearch.OnClickListener{...}) recyclerView?.adapter = adapter
2. 缩进错误:Adapter初始化逻辑写进了内部类
- AdapterSearch类中给展示列表赋值的
init{search=li}块,因缩进位置错误,实际归属内部类ShoeHolder的作用域,并非AdapterSearch类的初始化逻辑 - 这导致Adapter实例化完成后,用于承载展示数据的列表始终为空,即使过滤逻辑执行,也没有可渲染的数据
- 修复方式:将初始化逻辑移到AdapterSearch类的顶层作用域:
class AdapterSearch( private val originalList: ArrayList<NewShoe>, val onClickListener: OnClickListener ) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), Filterable { // 独立维护原始数据源和展示数据源 private val displayList = ArrayList<NewShoe>() private lateinit var mcontext: Context interface OnClickListener { fun onItemClick(position: Int, shoe: NewShoe) } class ShoeHolder(itemView: View) : RecyclerView.ViewHolder(itemView) // 初始化逻辑放在Adapter顶层 init { displayList.addAll(originalList) } }
3. Filter实现的并发问题
- 原Filter的
performFiltering方法运行在子线程,直接修改Adapter的主线程展示列表,会导致数据渲染异常 - 修复后的标准Filter实现:
override fun getFilter(): Filter { return object : Filter() { override fun performFiltering(constraint: CharSequence?): FilterResults { val query = constraint?.toString()?.trim() ?: "" val filteredList = ArrayList<NewShoe>() if (query.isEmpty()) { // 搜索关键词为空时加载完整原数据 filteredList.addAll(originalList) } else { // 匹配名称、型号、价格规则 for (item in originalList) { val matchName = item.name.lowercase(Locale.ROOT).contains(query.lowercase(Locale.ROOT)) val matchModel = item.model.lowercase(Locale.ROOT).contains(query.lowercase(Locale.ROOT)) val matchPrice = item.price.toString().contains(query) if (matchName || matchModel || matchPrice) { filteredList.add(item) } } } return FilterResults().apply { values = filteredList } } override fun publishResults(constraint: CharSequence?, results: FilterResults?) { // 在主线程更新展示列表 val resultList = results?.values as? ArrayList<NewShoe> ?: arrayListOf() displayList.clear() displayList.addAll(resultList) notifyDataSetChanged() } } }
4. 点击事件取值错位
- Adapter回调的position是基于过滤后的展示列表的,但原Fragment逻辑直接用原始列表
s[position]取值,搜索过滤状态下位置对应的数据完全错乱 - 修复方式:点击回调直接传递对应位置的实体对象:
// onBindViewHolder中的点击逻辑 holder.itemView.setOnClickListener { val pos = holder.bindingAdapterPosition onClickListener.onItemClick(pos, displayList[pos]) }
对应Fragment的回调逻辑同步修改:
adapter = AdapterSearch(s, object: AdapterSearch.OnClickListener { override fun onItemClick(position: Int, shoe: NewShoe) { val intent = Intent(activity, BuyingProducts::class.java) intent.putExtra("price", shoe.price) intent.putExtra("name", shoe.name) intent.putExtra("model", shoe.model) intent.putExtra("sizes", shoe.sizes) intent.putExtra("picture", shoe.image) intent.putExtra("spec", sp) startActivity(intent) } })
5. 冗余逻辑清理
- 原
onQueryTextChange回调中重复调用了两次adapter.filter.filter(newText),删除多余调用:
override fun onQueryTextChange(newText: String?): Boolean { adapter.filter.filter(newText) return true }
- 按照开发规范将
super.onViewCreated(view, savedInstanceState)移到方法开头调用,避免视图状态异常。
内容的提问来源于stack exchange,提问作者Alex Madaras
相关产品推荐
相关产品推荐

