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

跨Fragment传值时Shared MutableLiveData值为null的问题排查

问题分析与解决方案

核心原因

  1. ViewModel实例独立,初始值为null
    每个Fragment通过by viewModels()获取的WeatherScreenViewModel都是独立实例,天气Fragment每次被创建时,新ViewModel的city2默认值为null。switchMap会在city2的任何值变化(包括初始的null值)时触发,导致第一次以null为参数执行请求逻辑,随后调用setCity()又触发一次正常请求,最终重复获取数据。

  2. 参数处理逻辑的日志误导
    从主页跳转时,日志是在setCity()之后打印,所以能看到city2有值;而从收藏Fragment跳转时,先打印未赋值的city2,所以显示为null——这只是日志顺序导致的表象,本质问题是ViewModel初始化时的默认null值触发了额外请求。

解决方案

方案1:规避null触发无效请求

修改ViewModel中city2的初始值,并在switchMap中增加有效性判断:

// ViewModel中修改city2的定义
val city2 = MutableLiveData<String>("")

// 修改switchMap逻辑
val transformationWeather = city2.switchMap { cityName ->
    liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
        if (cityName.isNullOrEmpty()) {
            emit(Resource.Error("Invalid city name"))
            return@liveData
        }
        val geoResult = geoCoderRepository.cityToLongLat(cityName)
        if (geoResult.status is Success) {
            val list = listOf(
                geoResult.status.data!!.lat,
                geoResult.status.data!!.long!!
            )
            val notNullList: List<Double> = list.filterNotNull()
            emit(weatherRepository.fetchWeather(notNullList))
        }
    }
}

这样ViewModel初始化时city2是空字符串,switchMap会触发但直接返回错误,不会执行无效请求;当调用setCity()传入有效城市名时,才触发正常请求,避免重复。

方案2:使用Activity级共享ViewModel

如果需要跨Fragment共享城市状态,将所有Fragment的ViewModel获取方式改为by activityViewModels(),让ViewModel作用域提升到Activity级别,所有Fragment共享同一个实例:

// 主页Fragment、收藏Fragment、天气Fragment统一修改
private val viewModel : WeatherScreenViewModel by activityViewModels()

这种方式会保留ViewModel状态直到Activity销毁,适合需要跨页面共享状态的场景。

方案3:优化天气Fragment参数处理逻辑

统一参数获取逻辑,避免分支代码导致的混淆:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    val targetCity = arguments?.getString("city") ?: arguments?.getString("fav_city")
    targetCity?.let {
        city = it
        viewModel.setCity(it)
        Log.d("target_city", it)
    } ?: run {
        // 无有效城市名时的处理逻辑
    }
}

关于单独为city创建ViewModel的可行性

完全可行,本质是拆分状态管理职责。如果项目中城市状态需要在多个页面共享,单独抽离一个CitySharedViewModel(使用Activity级别作用域)能让代码职责更清晰,避免WeatherScreenViewModel承担过多状态管理工作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 15:15:06