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
相关产品推荐
相关产品推荐

