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

RecyclerView中NotifyDataSetChanged不生效,搜索筛选结果无法显示

SearchBar筛选后RecyclerView不显示过滤结果的解决方法

尝试用SearchBar对ArrayList进行筛选并将结果展示在RecyclerView中,日志显示数据已成功过滤,但过滤后的结果并未在RecyclerView中显示,求解决。

Activity代码

class RegisterActivity_7_Taste : AppCompatActivity(), OnTasteClickListener {

    private lateinit var binding : LayoutRegisterTasteBinding

    var taste_list = ArrayList<String>()

    private lateinit var adapter : RecyclerViewAdapter_Taste

    var check_taste = ArrayList<String>()

    val database = FirebaseDatabase.getInstance("url")
    val ref = database.getReference("path")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = LayoutRegisterTasteBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val taste_string = getSharedPreferences("data_booster", 0).getString("taste", "failed")
        taste_list = taste_string!!.split(",").distinct() as ArrayList<String>

        val editor = getSharedPreferences("data_cloud", 0).edit()

        binding.tasteSearch.setOnQueryTextListener(searchViewTextListener)

        binding.tasteSelect.layoutManager = LinearLayoutManager(this)
        adapter = RecyclerViewAdapter_Taste(taste_list, this)
        binding.tasteSelect.setAdapter(adapter)
    }

    var searchViewTextListener: SearchView.OnQueryTextListener =
        object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(s: String): Boolean {
                return false
            }

            override fun onQueryTextChange(s: String): Boolean {
                adapter.filter.filter(s)
                Log.d("RegisterActivity_8_Taste", "SearchView Text is Changed : $s")
                
                return false
            }
     }
}

原Adapter代码

class RecyclerViewAdapter_Taste(private val taste_list : ArrayList<String>, private val listener : OnTasteClickListener)
    : RecyclerView.Adapter<RecyclerViewAdapter_Taste.MyViewHolder>(), Filterable {
    inner class MyViewHolder(binding : FragmentRegisterTasteAdapterBinding) : RecyclerView.ViewHolder(binding.root) {
        val btn = binding.btn
        val root = binding.root
    }

    var TAG = "TasteRecyclerViewAdapter"
    var filteredTaste = ArrayList<String>()
    var itemFilter = ItemFilter()

    init {
        filteredTaste.addAll(taste_list)
    }

    var check : Boolean = false

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val binding : FragmentRegisterTasteAdapterBinding =
            FragmentRegisterTasteAdapterBinding.inflate(LayoutInflater.from(parent.context), parent, false)

        return MyViewHolder(binding)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val taste_name = taste_list[position].toString()

        holder.btn.text = taste_name

        holder.btn.setOnClickListener {
            if(check == false) {
                holder.btn.setBackgroundResource(R.drawable.btn_main_color)
                listener.onTasteClickAdd(taste_name)
                check = true
            }
            else {
                holder.btn.setBackgroundResource(R.drawable.btn_sub_color_light)
                listener.onTasteClickRemove(taste_name)
                check = false
            }
        }
    }

    override fun getItemCount(): Int {
        return taste_list.size
    }

    override fun getFilter() : Filter {
        return itemFilter
    }

    inner class ItemFilter : Filter() {
        override fun performFiltering(p: CharSequence?): FilterResults {
            val filterString = p.toString()
            val results = FilterResults()
            Log.d(TAG, "charSequence : $p")

            val filteredList : ArrayList<String> = ArrayList<String>()
            if(filterString.trim{it<= ' '}.isEmpty()) {
                results.values = taste_list
                results.count = taste_list.size
            }
            else {
                for (taste in taste_list) {
                    if (taste.contains(filterString)) {
                        filteredList.add(taste)
                    }
                }

                results.values = filteredList
                results.count = filteredList.size
            }

            return results
        }

        @SuppressLint("NotifyDataSetChanged")
        override fun publishResults(p0: CharSequence?, p1: FilterResults) {
            filteredTaste.clear()
            filteredTaste.addAll(p1.values as ArrayList<String>)
            notifyDataSetChanged()
        }
    }
}

问题原因及修复方案

核心问题:数据源不匹配

Adapter中虽维护了filteredTaste存储过滤后的结果,但onBindViewHolder和getItemCount仍在使用原始的taste_list,导致RecyclerView始终展示原始数据,而非过滤后的结果。

额外问题:选中状态全局共享

全局变量check会导致所有列表项的选中状态共用同一个值,点击任意一个按钮,所有按钮的状态都会同步变化,不符合需求。

修改后的Adapter代码

class RecyclerViewAdapter_Taste(private val taste_list : ArrayList<String>, private val listener : OnTasteClickListener)
    : RecyclerView.Adapter<RecyclerViewAdapter_Taste.MyViewHolder>(), Filterable {
    inner class MyViewHolder(binding : FragmentRegisterTasteAdapterBinding) : RecyclerView.ViewHolder(binding.root) {
        val btn = binding.btn
        val root = binding.root
        // 每个item独立维护选中状态
        var isChecked = false
    }

    var TAG = "TasteRecyclerViewAdapter"
    var filteredTaste = ArrayList<String>()
    var itemFilter = ItemFilter()

    init {
        filteredTaste.addAll(taste_list)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val binding : FragmentRegisterTasteAdapterBinding =
            FragmentRegisterTasteAdapterBinding.inflate(LayoutInflater.from(parent.context), parent, false)

        return MyViewHolder(binding)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        // 改用过滤后的数据源
        val taste_name = filteredTaste[position].toString()

        holder.btn.text = taste_name
        // 恢复item状态,防止滚动时状态错乱
        holder.btn.setBackgroundResource(if (holder.isChecked) R.drawable.btn_main_color else R.drawable.btn_sub_color_light)

        holder.btn.setOnClickListener {
            holder.isChecked = !holder.isChecked
            if(holder.isChecked) {
                holder.btn.setBackgroundResource(R.drawable.btn_main_color)
                listener.onTasteClickAdd(taste_name)
            }
            else {
                holder.btn.setBackgroundResource(R.drawable.btn_sub_color_light)
                listener.onTasteClickRemove(taste_name)
            }
        }
    }

    override fun getItemCount(): Int {
        // 返回过滤后的列表长度
        return filteredTaste.size
    }

    override fun getFilter() : Filter {
        return itemFilter
    }

    inner class ItemFilter : Filter() {
        override fun performFiltering(p: CharSequence?): FilterResults {
            val filterString = p.toString().lowercase() // 不区分大小写搜索(可选)
            val results = FilterResults()
            Log.d(TAG, "charSequence : $p")

            val filteredList : ArrayList<String> = ArrayList<String>()
            if(filterString.trim().isEmpty()) {
                filteredList.addAll(taste_list)
            }
            else {
                for (taste in taste_list) {
                    // 不区分大小写匹配
                    if (taste.lowercase().contains(filterString)) {
                        filteredList.add(taste)
                    }
                }
            }

            results.values = filteredList
            results.count = filteredList.size

            return results
        }

        @SuppressLint("NotifyDataSetChanged")
        override fun publishResults(p0: CharSequence?, p1: FilterResults) {
            filteredTaste.clear()
            filteredTaste.addAll(p1.values as ArrayList<String>)
            notifyDataSetChanged()
        }
    }
}

修改说明

  1. 数据源切换:将onBindViewHolder中的taste_list替换为filteredTaste,getItemCount返回filteredTaste.size,确保RecyclerView展示过滤后的结果。
  2. 选中状态独立:将选中状态变量移到MyViewHolder内部,每个列表项单独维护自己的选中状态,避免全局状态污染。
  3. 状态恢复:在onBindViewHolder中根据isChecked恢复按钮背景,防止RecyclerView滚动时item状态错乱。
  4. 可选优化:将搜索字符串和匹配字符串转为小写,实现不区分大小写的搜索,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 09:24:22