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

如何让ViewModel感知Preference DataStore变化并更新天气数据

实现DataStore变化时自动更新ViewModel的天气状态

我有一个存储地点列表的DataStore,相关代码如下。该列表用于从API获取天气数据,但目前向DataStore添加地点时,ViewModel无法感知变化并更新_weatherState获取新数据,希望解决这个问题。

DataStore相关代码

private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "location_list")
private val dataStoreKey = stringSetPreferencesKey(LOCATION_KEY)
suspend fun saveLocation(context: Context, data: String) {
    val locationSet = getLocations(context).first().toMutableSet()
    val isAdd = locationSet.add(data)
    if (isAdd) {
        val newSet = locationSet.toSet()
        context.dataStore.edit { preference ->
            preference[dataStoreKey] = newSet
        }
    }
}

suspend fun getLocations(context: Context): Flow<Set<String>> {
    val preferences = context.dataStore.data.first()
    if (preferences[dataStoreKey] != null) {
        return flowOf(preferences[dataStoreKey]!!)
    }
    return flowOf(emptySet())
}

获取天气数据的ViewModel代码

fun getWeatherData(context: Context) {
    getCurrentLocation(context) {currentLocation ->
        val weatherData = mutableListOf<Deferred<WeatherDataDaily>>()
        _weatherState.value.isLoading = true
        viewModelScope.launch {
            citiesRepository.getLocations(context).collect {
                val locationList = it.toMutableList()
                locationList.add(0, currentLocation.getLocationValue())
                for (value in locationList) {
                    val data = async {
                        repository.getWeatherData(value)
                    }
                    weatherData.add(data)
                }
                _weatherState.value = WeatherState(
                    weatherData.awaitAll(),
                    isInitialize = true
                )
            }
        }
        _weatherState.value.isLoading = false
        Log.d(TAG, "getWeatherData: ")
    }
}

解决方案

1. 修复DataStore的getLocations方法,使其持续监听数据变化

原来的getLocations使用first()只获取一次DataStore数据,修改后返回能持续监听的Flow,每次DataStore数据变更都会触发回调:

suspend fun getLocations(context: Context): Flow<Set<String>> {
    return context.dataStore.data
        .map { preferences ->
            preferences[dataStoreKey] ?: emptySet()
        }
}

2. 重构ViewModel的getWeatherData方法,正确响应数据变化

调整加载状态的时机,简化并发请求逻辑,确保每次DataStore更新都触发天气数据刷新:

fun getWeatherData(context: Context) {
    getCurrentLocation(context) { currentLocation ->
        viewModelScope.launch {
            citiesRepository.getLocations(context).collect { locationSet ->
                // 开始加载时更新状态
                _weatherState.value = _weatherState.value.copy(isLoading = true)
                // 构造包含当前位置的地点列表
                val locationList = locationSet.toMutableList().apply {
                    add(0, currentLocation.getLocationValue())
                }
                // 并发获取所有地点的天气数据
                val weatherData = locationList.map { location ->
                    async { repository.getWeatherData(location) }
                }.awaitAll()
                // 更新状态为加载完成并设置新数据
                _weatherState.value = WeatherState(
                    weatherData = weatherData,
                    isInitialize = true,
                    isLoading = false
                )
            }
        }
    }
}

关键说明

  • 修复后的getLocations会持续监听DataStore的变化,每次添加/删除地点时都会触发collect块执行。
  • 加载状态的更新被移到collect块内部,避免了之前提前设置为false的问题,确保用户能看到正确的加载提示。
  • 使用map+awaitAll简化了异步请求的代码,避免了可变列表的潜在问题,逻辑更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 15:32:02