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

filterProductUiState数据为空,UI无过滤结果显示问题排查

问题:Room过滤查询返回空结果,filteredProductList始终为空

我有两个UI状态:productHomeUiState(追踪实体数据)和filterProductUiState(追踪过滤后的数据)。现在的问题是,无论怎么调用Room的Product过滤查询,filterProductUiState里的filteredProductList始终是空的,导致UI的LazyColumn没有过滤结果显示,无法定位问题根源。


现有代码

ViewModel

class ProductViewModel(productRepository: ProductRepository) : ViewModel() {

    val productHomeUiState: StateFlow<ProductHomeUiState> =
        productRepository.getAllProductsStream().map { ProductHomeUiState(it) }
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(TIMEOUT_MILLIS),
                initialValue = ProductHomeUiState()
            )

    companion object {
        private const val TIMEOUT_MILLIS = 5_000L
    }

    private var isFilterActive = false

    fun isFilterActive(): Boolean {
        return isFilterActive
    }

    private var category: List<Category?> = emptyList()
    private var currency: String = ""
    private var startPrice: Double = 0.0
    private var endPrice: Double = 0.0
    private var startDate: String = ""
    private var endDate: String = ""
    private var company: String = ""

    private var categoryStrings: List<String> = emptyList()

    fun applyProductFilter(
        category: List<Category?>,
        currency: String,
        startPrice: Double,
        endPrice: Double,
        startDate: String,
        endDate: String,
        company: String
    ) {
        isFilterActive = true

        this.category = category
        this.currency = currency
        this.startPrice = startPrice
        this.endPrice = endPrice
        this.startDate = startDate
        this.endDate = endDate
        this.company = company


        val stringValues: List<String> = category
            .mapNotNull { it?.value }

        this.categoryStrings = stringValues

        Log.d("Core category", "Category=${stringValues}")
    }


    val filteredProductUiState: StateFlow<FilterProductUiState> =
        productRepository.filterCategory(categoryStrings)
            .map { FilterProductUiState(it) }
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(TIMEOUT_MILLIS),
                initialValue = FilterProductUiState(),
            )
}

data class ProductHomeUiState(
    val productList: List<Product> = listOf()
)

data class FilterProductUiState(
    val filterProductList: List<Product> = listOf()
)

查询相关代码

Dao
@Query("SELECT * FROM Product WHERE category IN (:categoryList)")
fun filterByCategory(categoryList: List<String>): Flow<List<Product>>
Repo接口
fun filterCategory(category: List<String>): Flow<List<Product>>
Offline-Repo实现
override fun filterCategory(category: List<String>): Flow<List<Product>> = productDao.filterByCategory(category)

问题根源

filteredProductUiState在ViewModel初始化时就执行了productRepository.filterCategory(categoryStrings),此时categoryStrings是空列表。后续调用applyProductFilter更新categoryStrings时,这个StateFlow不会重新触发查询——因为它只在初始化时捕获了当时的categoryStrings值,没有监听变量的变化。


修复方案

1. 改造ViewModel:用可观察状态保存过滤参数,自动触发查询

class ProductViewModel(productRepository: ProductRepository) : ViewModel() {

    val productHomeUiState: StateFlow<ProductHomeUiState> =
        productRepository.getAllProductsStream().map { ProductHomeUiState(it) }
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(TIMEOUT_MILLIS),
                initialValue = ProductHomeUiState()
            )

    companion object {
        private const val TIMEOUT_MILLIS = 5_000L
    }

    // 用StateFlow暴露过滤激活状态
    private val _isFilterActive = MutableStateFlow(false)
    val isFilterActive: StateFlow<Boolean> = _isFilterActive

    // 用MutableStateFlow保存所有过滤参数,确保变化能被监听
    private val _categoryStrings = MutableStateFlow(emptyList<String>())
    private val _currency = MutableStateFlow("")
    private val _priceRange = MutableStateFlow(0.0 to 0.0)
    private val _dateRange = MutableStateFlow("" to "")
    private val _company = MutableStateFlow("")

    fun applyProductFilter(
        category: List<Category?>,
        currency: String,
        startPrice: Double,
        endPrice: Double,
        startDate: String,
        endDate: String,
        company: String
    ) {
        _isFilterActive.value = true

        val stringValues = category.mapNotNull { it?.value }
        _categoryStrings.value = stringValues
        _currency.value = currency
        _priceRange.value = startPrice to endPrice
        _dateRange.value = startDate to endDate
        _company.value = company

        Log.d("Core category", "Category=${stringValues}")
    }

    // 监听所有过滤参数变化,自动触发最新查询
    val filteredProductUiState: StateFlow<FilterProductUiState> = combine(
        _categoryStrings,
        _currency,
        _priceRange,
        _dateRange,
        _company
    ) { categories, currency, priceRange, dateRange, company ->
        // 调用多条件查询(需改造Dao支持),或先查分类再做内存过滤
        productRepository.filterProducts(
            categories,
            currency,
            priceRange.first,
            priceRange.second,
            dateRange.first,
            dateRange.second,
            company
        )
    }.flatMapLatest { it } // 取消旧查询,只保留最新请求
        .map { FilterProductUiState(it) }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(TIMEOUT_MILLIS),
            initialValue = FilterProductUiState(),
        )
}

data class ProductHomeUiState(
    val productList: List<Product> = listOf()
)

data class FilterProductUiState(
    val filterProductList: List<Product> = listOf()
)

2. 改造Dao支持多条件查询(性能更优)

@Query("""
    SELECT * FROM Product 
    WHERE (:categoryList IS EMPTY OR category IN (:categoryList))
    AND (:currency IS EMPTY OR currency = :currency)
    AND (price BETWEEN :startPrice AND :endPrice OR (:startPrice = 0 AND :endPrice = 0))
    AND (date BETWEEN :startDate AND :endDate OR (:startDate IS EMPTY AND :endDate IS EMPTY))
    AND (:company IS EMPTY OR company = :company)
""")
fun filterProducts(
    categoryList: List<String>,
    currency: String,
    startPrice: Double,
    endPrice: Double,
    startDate: String,
    endDate: String,
    company: String
): Flow<List<Product>>

3. 同步更新Repo接口和实现

// Repo接口
fun filterProducts(
    categoryList: List<String>,
    currency: String,
    startPrice: Double,
    endPrice: Double,
    startDate: String,
    endDate: String,
    company: String
): Flow<List<Product>>

// Offline-Repo实现
override fun filterProducts(
    categoryList: List<String>,
    currency: String,
    startPrice: Double,
    endPrice: Double,
    startDate: String,
    endDate: String,
    company: String
): Flow<List<Product>> = productDao.filterProducts(categoryList, currency, startPrice, endPrice, startDate, endDate, company)

修复说明

  • 用MutableStateFlow保存过滤参数,确保参数变化能被实时监听
  • 用combine合并多个参数流,任何参数变化都会触发新查询
  • flatMapLatest确保只处理最新的查询请求,避免无效的旧请求占用资源
  • 多条件查询放在Room层执行,相比内存过滤更适合大数据量场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 21:07:14