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

Android SearchView实现同义词关联搜索匹配项的方法

Android 语义关联搜索功能实现方案

原有add()方法不生效的原因

  • 初始化ArrayAdapter时传入的arrayOf()生成的是不可变数组,适配器本身不支持对该数据源做增删操作,直接调用add()要么抛出异常要么操作无响应
  • 就算手动add成功,后续调用默认的filter()方法时,系统会用初始原始数据源重新做字符串包含匹配,手动添加的项会被直接覆盖
  • 原有分支判断存在逻辑冲突:多个if分支会先后触发多次filter操作,最后一次执行的filter结果会覆盖之前的所有操作

实现思路

  • 提前定义每个列表项对应的语义触发关键词映射表,替代零散的if判断
  • 自定义ArrayAdapter的过滤逻辑,替换默认的简单字符串包含匹配规则,实现语义关联匹配
  • 用可变列表作为适配器的数据源,支持动态更新展示内容

完整可运行代码

首先定义关键词映射和适配器:

// 语义映射配置:key为列表最终展示的项,value为所有可触发该项的关联关键词
val keywordMatchMap = mapOf(
    "distance" to listOf("kilometer", "mi", "distance"),
    "tax" to listOf("tax", "money", "bill"),
    "color" to listOf("hex", "rgb", "color")
)
// 全量原始列表项
val fullAppletList = listOf("distance", "tax", "color")
// 可变列表作为适配器的实际展示数据源
val displayList = ArrayList(fullAppletList)

// 自定义适配器重写过滤逻辑
val appletAdapter = object : ArrayAdapter<String>(
    this,
    android.R.layout.simple_list_item_1,
    displayList
) {
    override fun getFilter(): Filter {
        return object : Filter() {
            override fun performFiltering(constraint: CharSequence?): FilterResults {
                val filterResult = FilterResults()
                val inputQuery = constraint?.toString()?.trim()?.lowercase() ?: ""
                
                // 输入为空时返回全量列表
                if (inputQuery.isEmpty()) {
                    filterResult.values = fullAppletList
                    filterResult.count = fullAppletList.size
                    return filterResult
                }

                // 遍历语义映射表,匹配所有符合条件的项
                val matchedItems = mutableListOf<String>()
                for ((targetItem, triggerKeywords) in keywordMatchMap) {
                    // 匹配规则:输入包含关键词/关键词包含输入即命中,不区分大小写
                    if (triggerKeywords.any { 
                        it.contains(inputQuery) || inputQuery.contains(it) 
                    }) {
                        matchedItems.add(targetItem)
                    }
                }

                filterResult.values = matchedItems
                filterResult.count = matchedItems.size
                return filterResult
            }

            @Suppress("UNCHECKED_CAST")
            override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
                displayList.clear()
                val resultList = results?.values as? List<String> ?: emptyList()
                displayList.addAll(resultList)
                if (results != null && results.count > 0) {
                    notifyDataSetChanged()
                } else {
                    notifyDataSetInvalidated()
                }
            }
        }
    }
}

然后绑定SearchView监听,原有冗余判断全部删除:

binding.appletList.adapter = appletAdapter
binding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
    override fun onQueryTextSubmit(query: String): Boolean {
        binding.searchView.clearFocus()
        return false
    }

    override fun onQueryTextChange(newText: String): Boolean {
        // 直接触发自定义过滤器即可,不需要额外写contains判断
        appletAdapter.filter.filter(newText.trim())
        return false
    }
})

规则调整说明

  • 当前匹配规则为模糊匹配,比如输入kil即可命中kilometer关联的distance项,输入rg即可命中rgb关联的color项
  • 如果需要严格匹配完整关键词,只需要把performFiltering方法里的匹配条件替换为triggerKeywords.any { it == inputQuery }即可
  • 如果后续需要新增关联项,只需要在keywordMatchMap里加对应配置即可,不需要修改过滤逻辑

内容的提问来源于stack exchange,提问作者Marvil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 13:36:18