如何用LiveData与SearchView实现RecyclerView数据过滤更新
一、为什么Observer中的it是MutableList(而非LiveData)
你调用的viewModel.getFilteredReferenceItem(searchVal)返回的是LiveData<List<ReferenceItem>>,但observe方法的作用是监听LiveData内部数据的变化。当LiveData中的数据(也就是数据库查询返回的List<ReferenceItem>)更新时,会自动把这个数据传递给Observer的lambda表达式,所以it就是LiveData持有的实际数据(List<ReferenceItem>),而不是LiveData对象本身。
至于最终it能被传入sortReferenceItemList,说明这个方法内部要么把List<ReferenceItem>转换成了MutableList<AdapterReferenceItem>,要么你的DAO查询返回的List本身就是可变类型(Room默认返回不可变List,但可通过自定义转换实现可变)。
二、搜索栏无效果的修复方案
当前代码的问题是:你只在Fragment初始化时调用了一次getFilteredReferenceItem(searchVal)并观察,之后修改searchVal不会触发新的数据库查询——因为最初的LiveData是基于初始空字符串生成的,不会自动跟随searchVal变化。
步骤1:改造ViewModel,用LiveData监听搜索关键词变化
在ViewModel中添加保存搜索关键词的MutableLiveData,并通过Transformations.switchMap自动触发查询:
class YourViewModel(private val repository: YourRepository) : ViewModel() { // 保存搜索关键词,初始为空 private val searchQuery = MutableLiveData<String>("") // 根据搜索关键词自动更新查询结果 val filteredReferenceItems: LiveData<List<ReferenceItem>> = Transformations.switchMap(searchQuery) { query -> repository.getFilteredReferenceItem(query) } // 提供更新搜索关键词的方法 fun updateSearchQuery(query: String) { searchQuery.value = query } // 你的排序方法(若参数是List而非MutableList,建议修改参数类型,或内部转换) fun sortReferenceItemList(list: List<ReferenceItem>): MutableList<AdapterReferenceItem> { // 原逻辑,若需要MutableList,可先转成可变:val mutableList = list.toMutableList() // ... 你的分组添加头部逻辑 } }
注:如果之前ViewModel直接调用DAO,建议把DAO的调用封装到Repository中(符合MVVM架构规范),如果不想改,也可以直接在switchMap中调用
dao.getFilteredReferenceItem(query)。
步骤2:修改Fragment的观察逻辑
在Fragment的onViewCreated中,改为观察ViewModel中定义的filteredReferenceItems:
@SuppressLint("NotifyDataSetChanged") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setRecyclerView(view) // 观察自动更新的过滤结果 viewModel.filteredReferenceItems.observe(viewLifecycleOwner) { referenceList -> refAdapter.referenceItems = viewModel.sortReferenceItemList(referenceList) refAdapter.notifyDataSetChanged() } // 初始化搜索栏 initSearchView(view) }
步骤3:修复搜索栏的回调逻辑
修改搜索栏代码,调用ViewModel的updateSearchQuery方法触发查询更新:
private fun initSearchView(view: View) { val searchView = view.findViewById<SearchView>(R.id.search_ref) searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { query?.let { viewModel.updateSearchQuery(it) } searchView.clearFocus() // 可选:提交后收起键盘 return true } override fun onQueryTextChange(newText: String?): Boolean { viewModel.updateSearchQuery(newText ?: "") return true } }) }
生效原因
searchQuery是MutableLiveData,当调用updateSearchQuery修改它的值时,Transformations.switchMap会自动触发新的数据库查询(调用DAO的getFilteredReferenceItem)。- 查询结果更新后,
filteredReferenceItems这个LiveData会自动通知Observer,从而更新RecyclerView的数据源。
内容的提问来源于stack exchange,提问作者Francky380

