当Activity的searchView更改存储库中的数据时,片段(和viewmodel)中的实时数据不会触发onChange更新

时间:2020-10-21 06:45:34

标签: android kotlin android-room repository-pattern android-livedata

我正在使用带有MVVM +存储库+带有改造的NodeJS后端结构的应用程序。我面临的问题如下:

  1. 我的活动中有一个searchView(用于输入城市名称)。此searchView的onSubmit调用以city为参数的viewmodel函数,进而调用存储库函数以使用改造从后端获取数据。我已经对此进行了测试,并且可以正确提取数据并在Room数据库中对其进行更新。如果我在数据库中打印数据,则可以看到所有提取的数据。
  2. 现在,我想用此数据更新片段UI。早些时候,我已将Fragment与自己的Viewmodel绑定在一起,该Viewmodel返回一个“延迟延迟的LiveData”,并观察从数据库返回的数据(Livedata) 我的问题是片段UI无法获取此更新的数据。流程很简单,活动从存储库中的视图模型设置数据,而片段则观察该数据的变化。希望我能说清楚。我已经在下面附加了我的代码。

调用ViewModel的活动代码

searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String): Boolean {
                runBlocking {
                    viewModel.setQueryToRepository(query)
                }

活动的视图模型可更新存储库中的城市

suspend fun setQueryToRepository(city: String){
        weatherRepository.setCity(city)
    }

存储库内部的实现

private var city: String = ""
override suspend fun setCity(city: String){
        this.city = city
        Log.d("data", "city: ${this.city}")
        getSearchedWeather()
    }

    override suspend fun getSearchedWeather(): LiveData<out CurrentWeatherEntity> {
        return withContext(Dispatchers.IO) {
            if (city == ""){
                return@withContext currentWeatherDAO.getCurrentWeatherFromDB(34.04563903808594,-118.24163818359375)
            }
            val (lat, lng) = getLocationFromAddress(city)
            Log.d("data","lat: $lat, lon: $lng, city: $city")
            initFetchSearchedWeatherData(lat, lng, city)
            Log.d("data", "return value is: ${currentWeatherDAO.getByCity(city)}")
            return@withContext currentWeatherDAO.getCurrentWeatherFromDB(1.352083, 103.819836)
        }
    }

initFetchSearchedWeatherData(lat,lng,city)函数决定是否进行提取(基于数据的新鲜度),如果是,它将调用改造并更新其Livedata,我在存储库的init函数中观察到的是这样的。 / p>

init{
        weatherNetworkDataSource.downloadedCurrentWeather.observeForever{ newCurrentWeather ->
            Log.d("data", "changed data is, lat: ${newCurrentWeather.location.latitude}, lng: ${newCurrentWeather.location.longitude}")
            persistFetchedCurrentWeather(newCurrentWeather)
        }

persistFetchedCurrentWeather()函数只是将数据向上插入数据库的current_weather表中。

private fun persistFetchedCurrentWeather(fetchedWeather: CurrentWeatherEntity){
        Log.d("data", "data in persist is, lat: ${fetchedWeather.location.latitude}, lng: ${fetchedWeather.location.longitude}")
        GlobalScope.launch(Dispatchers.IO) {
            currentWeatherDAO.upsertCurrentWeatherData(fetchedWeather)
            val data = currentWeatherDAO.getAllData()
            data.map {
                Log.d("data", "entry is ${it.location}")
            }
        }

    }

所以我最终从表返回Livedata为:

return@withContext currentWeatherDAO.getWeatherByCity(city)

为方便起见,我将总结存储库中的功能。

  1. SearchView的onSubmit活动调用存储库的setCity,后者将查询设置为城市并调用getSearchedWeather()
  2. getSearchedWeather()决定是否进行api调用并返回数据(来自db的Livedata)
  3. 我的片段通过我的片段视图模型观察此Livedata,并应更新UI。

我从其视图模型观察Livedata的片段

viewModel = ViewModelProvider(requireActivity(), viewModelFactory)
            .get(WeatherSearchResultViewModel::class.java)
        bindUI()
val searchedWeather = viewModel.getDataFromRepository.await()

        searchedWeather.observe(viewLifecycleOwner, Observer {
            if (it == null) {
                group_ready.visibility = View.GONE
                group_loading.visibility = View.VISIBLE
                return@Observer
            }

            // Update UI here
        })

以及Fragment的视图模型,将其作为Livedata从存储库的getSearchedWeather(上面添加的代码)中以Livedata的形式返回

val getDataFromRepository by lazyDeferred {
        weatherRepository.getSearchedWeather()
    }

0 个答案:

没有答案