Android Paging3中SearchView过滤PagingDataAdapter数据不更新问题
问题原因
你当前的实现无法刷新列表,核心是用法和Paging3的设计逻辑完全冲突:
- 你自定义了
AsyncListDiffer做数据提交,但Paging3配套的PagingDataAdapter本身已经内置了专属Differ实现,你自己维护的mDiffer和适配器实际绑定的数据链路完全隔离,哪怕你给自定义mDiffer传入了搜索结果,适配器根本读不到这部分数据,自然不会触发界面更新。 - 你在
publishResults里手动调用notifyDataSetChanged()是错误操作,不管是AsyncListDiffer还是PagingDataAdapter,界面刷新都是靠差分比对结果自动触发的,手动调用全量刷新会打断差分计算流程,反而会导致列表不刷新。 - 不要在Paging3的适配器里用原生
Filter类做本地过滤,Paging3的所有数据都通过PagingData流流转,在适配器层直接裁剪数据会破坏分页状态,等你清空搜索词回到全量列表时,会出现数据丢失、分页加载失效的问题。
正确实现步骤
1. 把搜索逻辑移到ViewModel层,不要写在适配器里
Paging3的搜索过滤应该通过切换数据流实现,关键词变化时自动切换到对应数据源,不要在适配器层改数据:
class MyViewModel : ViewModel() { // 持有搜索关键词,初始为空表示展示全量数据 private val searchQuery = MutableStateFlow("") // 给SearchView调用,更新搜索关键词 fun setSearchQuery(query: String) { searchQuery.value = query.trim() } // 关键词变化时自动切换数据源,上一个未完成的分页请求会被自动取消 val pagingDataFlow = searchQuery .debounce(300) // 加300ms防抖,避免输入过程中频繁查库 .distinctUntilChanged() .flatMapLatest { keyword -> if (keyword.isEmpty()) { // 无关键词时加载全量分页数据 repository.getPagedAllData() } else { // 有关键词时加载匹配搜索结果的分页数据 repository.searchPagedData(keyword) } }.cachedIn(viewModelScope) }
如果用Room做本地存储,直接在DAO层写带查询参数的PagingSource即可,Room原生支持Paging3,不需要自己写分页逻辑。
2. 精简适配器代码
删掉你自定义的mDiffer、自定义submitList方法、所有Filter相关逻辑,适配器直接继承PagingDataAdapter,只保留DiffUtil和基础视图绑定逻辑:
class MyAdapter : PagingDataAdapter<Data, MyAdapter.VH>(DataComparator) { object DataComparator : DiffUtil.ItemCallback<Data>() { override fun areItemsTheSame(oldItem: Data, newItem: Data): Boolean { return oldItem.mobileNo == newItem.mobileNo } override fun areContentsTheSame(oldItem: Data, newItem: Data): Boolean { return oldItem == newItem } } inner class VH(itemView: View) : RecyclerView.ViewHolder(itemView) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH { val view = LayoutInflater.from(parent.context) .inflate(R.layout.item_data, parent, false) return VH(view) } override fun onBindViewHolder(holder: VH, position: Int) { val item = getItem(position) ?: return // 这里写你的数据绑定逻辑,比如holder.tvMobile.text = item.mobileNo } }
3. 页面层绑定数据和搜索事件
在Activity/Fragment中收集ViewModel的分页数据流,同时给SearchView设置监听,把输入内容传给ViewModel:
// 先初始化适配器 private val adapter by lazy { MyAdapter() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) recyclerView.adapter = adapter // 收集分页数据,自动提交给适配器 lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.pagingDataFlow.collectLatest { adapter.submitData(it) } } } // 绑定SearchView输入事件 searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?) = false override fun onQueryTextChange(newText: String?): Boolean { viewModel.setSearchQuery(newText ?: "") return true } }) }
补充说明
- 如果需要做内存层面的本地数据过滤,不要用Filter类,直接对PagingData流用
filter、map操作符处理后再提交给适配器,不要直接修改适配器内部的数据集。 - 永远不要在PagingDataAdapter里手动调用
notifyDataSetChanged(),所有数据更新都通过submitData提交新的PagingData完成,差分计算完成后会自动刷新对应项。 - 如果搜索是走网络请求,同样可以复用上面的流切换逻辑,只需要把Repository层的实现换成网络分页数据源即可。
内容的提问来源于stack exchange,提问作者Kumar
相关产品推荐
相关产品推荐

