基于Android架构组件:SearchView过滤LiveData驱动的RecyclerView列表问题
既然你用的是Android Architecture Components,那咱们可以从Repository层入手,结合Room的查询能力和LiveData来实现实时的搜索过滤,同时保留数据的实时更新特性。下面分两种场景给你具体实现步骤:
方案一:数据库层面过滤(推荐,大数据量友好)
这种方式直接让Room根据搜索关键词查询数据,返回过滤后的LiveData,性能更好,而且自动响应数据库的变化。
1. 在Dao中添加带搜索参数的查询方法
在你的GroupVcDao里新增一个返回LiveData<List<GroupVc>>的查询方法,用SQL的LIKE来匹配名称:
@Dao interface GroupVcDao { // 原有的全量查询方法 @Query("SELECT * FROM group_vc") fun getAllGroupVc(): LiveData<List<GroupVc>> // 新增的搜索过滤查询(支持模糊匹配) @Query("SELECT * FROM group_vc WHERE LOWER(name) LIKE LOWER(:searchQuery)") fun searchGroupVc(searchQuery: String): LiveData<List<GroupVc>> }
这里用LOWER()是为了实现大小写不敏感的搜索,如果你不需要的话可以去掉。
2. 在Repository层封装搜索逻辑
在你的Repository里,添加一个方法处理搜索请求,同时兼容空搜索(返回全量数据):
class GroupVcRepository(private val groupVcDao: GroupVcDao) { // 原有的全量LiveData val allGroupVc: LiveData<List<GroupVc>> = groupVcDao.getAllGroupVc() // 搜索方法,返回过滤后的LiveData fun searchGroupVc(query: String): LiveData<List<GroupVc>> { // 处理空查询:如果关键词为空,返回全量数据 val searchQuery = if (query.isBlank()) { "%" // 匹配所有数据 } else { "%$query%" } return groupVcDao.searchGroupVc(searchQuery) } }
3. 在ViewModel中管理搜索状态
ViewModel需要维护当前的搜索关键词,并且通过switchMap自动转换为对应的结果LiveData:
class GroupVcViewModel(private val repository: GroupVcRepository) : ViewModel() { // 用于保存搜索关键词的MutableLiveData private val _searchQuery = MutableLiveData<String>("") // 自动根据关键词更新的结果LiveData val filteredGroupVc: LiveData<List<GroupVc>> = _searchQuery.switchMap { query -> repository.searchGroupVc(query) } // 供UI调用的方法,更新搜索关键词 fun updateSearchQuery(query: String) { _searchQuery.value = query } }
switchMap的好处是:每当搜索关键词变化时,会自动切换到新的查询LiveData,无需手动管理订阅关系。
4. 在UI层绑定SearchView和RecyclerView
在你的Activity/Fragment中,监听SearchView的文本变化,同时观察ViewModel的结果更新RecyclerView:
// 初始化ViewModel val viewModel = ViewModelProvider(this)[GroupVcViewModel::class.java] // 绑定RecyclerView适配器 val adapter = GroupVcAdapter() recyclerView.adapter = adapter // 观察过滤后的列表,自动更新适配器 viewModel.filteredGroupVc.observe(this) { groupList -> adapter.submitList(groupList) } // 设置SearchView的文本监听 searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { query?.let { viewModel.updateSearchQuery(it) } return true } override fun onQueryTextChange(newText: String?): Boolean { newText?.let { viewModel.updateSearchQuery(it) } return true } })
这样,每当你在SearchView中输入文本,ViewModel会自动触发数据库查询,RecyclerView也会实时展示过滤后的结果。
方案二:内存层面过滤(小数据量适用)
如果你的GroupVc数据量不大,也可以直接在内存中过滤全量列表,无需修改数据库查询逻辑:
1. 在ViewModel中处理内存过滤
class GroupVcViewModel(private val repository: GroupVcRepository) : ViewModel() { private val _searchQuery = MutableLiveData<String>("") private val allGroupVc = repository.allGroupVc // 内存过滤后的结果LiveData val filteredGroupVc: LiveData<List<GroupVc>> = Transformations.switchMap(_searchQuery) { query -> Transformations.map(allGroupVc) { groupList -> if (query.isBlank()) { groupList } else { groupList.filter { it.name.contains(query, ignoreCase = true) } } } } fun updateSearchQuery(query: String) { _searchQuery.value = query } }
这种方式的好处是不需要改动Dao层,适合数据量小的场景,但大数据量时性能不如数据库层面过滤。
2. UI层绑定和方案一完全一致
同样监听SearchView的文本变化,调用updateSearchQuery即可。
额外小提示
- 可以给SearchView设置
setIconifiedByDefault(false),让搜索框默认展开,提升用户体验。 - 如果用数据库过滤,Room会自动缓存查询结果,重复搜索相同关键词时不会重复查询数据库,性能有保障。
内容的提问来源于stack exchange,提问作者LA_Homie

