LiveData观察者多次触发问题

6

我在我的项目中遇到了设置MVVM的问题,一切似乎都很顺利,除了我注意到我的LiveData对象的观察器被多次调用。有时同一个LiveData对象更新一次就会被调用4-5次。

主活动上承载了多个片段,所有片段都连接到相同的ViewModel,该ViewModel连接到我的存储库,然后使用Retrofit向服务器发出API请求。

然后,在每个片段中都有单独的观察器,观察ViewModel中相同的LiveData对象的更改。当使用单一片段时,我没有遇到同一更改的多次观察问题,但在将项目分支化为多个片段后,我注意到观察器被频繁调用。

我尝试将观察器全部更改为使用viewLifecycleOwner,但无济于事。

以下是一个片段的示例,它们在观察LiveData方面本质上是相同的,只是它们更新UI的不同部分。

override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProviders.of(this, viewModelFactory)
                .get(WeatherViewModel::class.java)
        bindUI()
    }

    private fun bindUI() = launch {
        val currentWeatherResponse = viewModel.weatherResponse.await()

        currentWeatherResponse.observe(viewLifecycleOwner, Observer {
            if(it == null) return@Observer
            Log.i("CurrentWeatherFragment", "Observed")
            val currentWeather = it.currentWeather.first()
            updateTemperature(currentWeather.temperature, currentWeather.tempMin, currentWeather.tempMax)
            updateWind(currentWeather.windSpeed, currentWeather.windDirName)
            updateHumidity(currentWeather.humidity)

        })
    }

这是每个片段都连接到的ViewModel:

class WeatherViewModel(
        private val forecastRepository: IForecastRepository
) : ViewModel() {

    val weatherResponse by lazyDeferred {
        forecastRepository.getWeatherResponse()
    }

}

我的代码库中的天气响应方法:

    override suspend fun getWeatherResponse(): LiveData<out DetailedPrediction> {
        return withContext(Dispatchers.IO) {
            initWeatherData()
            println("Get Weather response method")
            println(currentWeatherDao.getWeatherResponse().value)
            return@withContext currentWeatherDao.getWeatherResponse()
        }
    }

天气 DAO 接收来自 saveWeatherResponse 方法的数据发布:

    private val weatherResponse = MutableLiveData<DetailedPrediction>()
    private val radarImages = MutableLiveData<RadarImageList>()

    //TODO Return weather response from shared preferences
    override fun getWeatherResponse(): LiveData<DetailedPrediction> {
        return weatherResponse
    }

我希望能够通过这个单一的LiveData事件来更新所有UI元素,目前它可以正常工作,但观察者触发得太频繁了,我实在想不出为什么。


我不明白在这里使用Kodein的意义是什么? - romainbsl
weatherResponse被更新时,所有订阅该LiveData的观察者都会被通知是正常的。您是在说每个观察者实例在单个LiveData更新时会被多次触发吗? - Sanlok Lee
@SanlokLee 嗯,似乎有4个观察者中的2个在同一请求中被调用了约5次。 这是来自单个请求的日志:I/Summary Fragment: 观察到 I/DailyWeatherFragment: 观察到 I/CurrentWeatherFragment: 观察到 I/DailyWeatherFragment: 观察到 I/CurrentWeatherFragment: 观察到 I/DailyWeatherFragment: 观察到 I/CurrentWeatherFragment: 观察到 I/CurrentWeatherFragment: 观察到 I/DailyWeatherFragment: 观察到 - Michael Bell
@SanlokLee 看起来随着时间的推移,它似乎正在添加更多的观察者,如果我让应用程序保持打开状态15分钟,同一个观察者会为一个请求触发 ~20 次。就好像每次都创建了一个新实例,这正是我认为使用 viewLifecycleOwner 修复的问题。 - Michael Bell
1个回答

8
我很惊讶自己花了这么长时间才发现一个简单的错误,但如果有人遇到这个问题(我怀疑),我是在每次观察时添加片段而不是替换片段,这意味着为每个片段创建了一个全新的观察者。
以下是旧代码:

    fun addDailyWeatherFragment() {
        val fragmentTransaction: FragmentTransaction = fragmentManager!!.beginTransaction()
        val dailyWeatherFragment = DailyWeatherFragment()
        fragmentTransaction.add(R.id.fragmentContainer, dailyWeatherFragment)
        fragmentTransaction.commit()
    }

固定的代码:


    fun addDailyWeatherFragment() {
        val fragmentTransaction: FragmentTransaction = fragmentManager!!.beginTransaction()
        val dailyWeatherFragment = DailyWeatherFragment()
        fragmentTransaction.replace(R.id.fragmentContainer, dailyWeatherFragment)
        fragmentTransaction.commit()
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接