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

Kotlin Android中AlertDialog无法更新列表:筛选后排序失效问题

解决筛选后无法再次排序及筛选列表为空的问题

核心问题分析

  • 重复观察LiveData:每次点击筛选按钮都调用viewModel.products.observe,会累积多个观察者,导致数据处理逻辑混乱;且LiveData回调是异步的,直接在回调里操作filteredList会因为时序问题拿不到最新数据。
  • 初始数据加载错误:onViewCreated中直接执行filteredList.addAll(adapter.recyclerListDiffer.currentList)时,viewModel.products还未完成回调,currentList为空,导致初始filteredList无数据。
  • 筛选逻辑时序错误:在遍历filterArrayBool的循环内判断selectedItemList.size,此时selectedItemList还未收集完所有选中的分类,筛选条件错误;且多分类筛选时存在条件遗漏(比如4个分类的筛选漏了第二个选项)。
  • 状态维护缺失:没有保存当前的筛选状态,再次筛选后排序逻辑找不到正确的数据源;filterArrayBool的重置逻辑无效(forEach { it==false }只是比较,未修改数组)。

修复后的代码

@AndroidEntryPoint
class ProductFragment : Fragment(R.layout.fragment_product) {

    private var fragmentBinding: FragmentProductBinding? = null

    @Inject
    lateinit var viewModel: HomeViewModel
    @Inject
    lateinit var adapter: ProductsAdapter

    // 保存原始完整商品列表
    private val originalProducts = mutableListOf<Product>()
    // 当前选中的筛选分类
    private val selectedCategories = mutableSetOf<String>()
    // 当前排序类型
    private var currentSortType = SortType.BEST_MATCH

    // 定义排序类型枚举,避免字符串判断的误差
    private enum class SortType {
        BEST_MATCH, PRICE_ASC, PRICE_DESC
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val binding = FragmentProductBinding.bind(view)
        fragmentBinding = binding

        binding.productsRecycler.adapter = adapter
        binding.productsRecycler.layoutManager = StaggeredGridLayoutManager(2, RecyclerView.VERTICAL)

        // 只观察一次LiveData,获取原始数据
        viewModel.getAllProducts()
        viewModel.products.observe(viewLifecycleOwner) { response ->
            response.data?.let { products ->
                originalProducts.clear()
                originalProducts.addAll(products)
                // 首次加载时应用默认的筛选和排序
                updateDisplayList()
            }
        }

        adapter.setOnItemClickListener {
            val action = ProductFragmentDirections.actionProductFragmentToDetailScreenFragment(it)
            findNavController().navigate(action)
        }

        // 返回按钮
        binding.productsBackbutton.setOnClickListener {
            findNavController().popBackStack()
        }

        // 排序按钮逻辑
        val sortArray = arrayOf("Best Match", "Price Asc", "Price Desc")
        binding.productsSortbutton.setOnClickListener {
            var selectedIndex = when (currentSortType) {
                SortType.BEST_MATCH -> 0
                SortType.PRICE_ASC -> 1
                SortType.PRICE_DESC -> 2
            }

            MaterialAlertDialogBuilder(requireContext())
                .setSingleChoiceItems(sortArray, selectedIndex) { _, which ->
                    selectedIndex = which
                }
                .setPositiveButton("Sort") { _, _ ->
                    currentSortType = when (selectedIndex) {
                        0 -> SortType.BEST_MATCH
                        1 -> SortType.PRICE_ASC
                        2 -> SortType.PRICE_DESC
                        else -> SortType.BEST_MATCH
                    }
                    updateDisplayList()
                    binding.productsRecycler.smoothScrollToPosition(0)
                }
                .show()
        }

        // 筛选按钮逻辑
        val filterArray = arrayOf("Electronics", "Jewelery", "Men's Clothing", "Women's Clothing")
        val filterArrayBool = booleanArrayOf(false, false, false, false)

        binding.productsFilterbutton.setOnClickListener {
            // 更新复选框状态为当前选中的分类
            filterArray.forEachIndexed { index, category ->
                filterArrayBool[index] = selectedCategories.contains(category.lowercase())
            }

            MaterialAlertDialogBuilder(requireContext())
                .setCancelable(false)
                .setMultiChoiceItems(filterArray, filterArrayBool) { _, which, isChecked ->
                    val category = filterArray[which].lowercase()
                    if (isChecked) {
                        selectedCategories.add(category)
                    } else {
                        selectedCategories.remove(category)
                    }
                }
                .setPositiveButton("FILTER") { _, _ ->
                    updateDisplayList()
                    binding.productsRecycler.smoothScrollToPosition(0)
                }
                .setNeutralButton("Show All") { _, _ ->
                    selectedCategories.clear()
                    filterArrayBool.fill(false)
                    updateDisplayList()
                    binding.productsRecycler.smoothScrollToPosition(0)
                }
                .show()
        }
    }

    // 统一处理筛选和排序,生成要显示的列表
    private fun updateDisplayList() {
        var displayList = originalProducts.toList()

        // 应用筛选
        if (selectedCategories.isNotEmpty()) {
            displayList = displayList.filter { product ->
                selectedCategories.contains(product.category)
            }
        }

        // 应用排序
        displayList = when (currentSortType) {
            SortType.PRICE_ASC -> displayList.sortedBy { it.price.toDouble() }
            SortType.PRICE_DESC -> displayList.sortedByDescending { it.price.toDouble() }
            SortType.BEST_MATCH -> displayList // 原始顺序即为最佳匹配
        }

        // 提交给Adapter
        adapter.recyclerListDiffer.submitList(displayList)
    }

    override fun onDestroyView() {
        super.onDestroyView()
        fragmentBinding = null
    }
}

关键修改说明

  • 统一数据处理逻辑:新增updateDisplayList()方法,基于原始数据统一处理筛选和排序,避免多次操作数据源导致的混乱。
  • 状态维护:用selectedCategories保存当前选中的筛选分类,currentSortType保存当前排序类型,确保每次操作都基于最新状态。
  • 避免重复观察:只在onViewCreated中观察一次viewModel.products,拿到原始数据后保存,后续所有操作都基于这份原始数据。
  • 修复筛选逻辑:先收集所有选中的分类,再统一筛选;修复多分类筛选的条件遗漏问题。
  • 优化排序逻辑:用枚举类替代字符串判断,避免拼写错误;弹窗初始化时自动选中当前排序类型,提升用户体验。
  • 修复状态重置:用filterArrayBool.fill(false)正确重置复选框状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:50:25