【问题标题】:Best Way to "Refresh" LiveData Provided by Room DatabaseRoom Database 提供的“刷新”LiveData 的最佳方式
【发布时间】:2020-02-16 04:08:21
【问题描述】:

我目前正在使用 Room 来存储单词翻译列表,并将查询作为 LiveData 返回以监控插入和更新。但是,当我需要重新获取不同源语言的翻译时遇到了问题(我目前的策略是将 livedata 重新分配给房间查询的结果)。

我使用以下 SQL 查询获取要翻译的语言和特定语言的翻译

@Dao
interface TranslationDatabaseDao {
   ...

   //Returns all pairs of languages to translate to/from
   @Query("SELECT * FROM language_pairs")
   fun getAllLanguagePairs(): LiveData<List<LanguagePair>>

   //Returns translations with the specified source language
   @Query("SELECT * FROM translations WHERE sourceLanguage = :language")
   fun getTranslations(language: String): LiveData<List<TranslationResult>>

   ...
}

我在实例化视图模型时调用它,并在用户更改语言时再次调用(参见下面的changeLanguage(...))。

class translationViewmodel(private val database: TranslationDatabaseDao, initLanguage: String): ViewModel() {
   ...

   val languages: LiveData<List<LanguagePair>> = database.getAllLanguagePairs()
   val currentLanguages = Transformations.map(languages) { allLanguages ->
      allLanguages?.let {
         it[0] //Get the first language in the list
      }
   }

   var translations: LiveData<List<TranslationResult>> = database.getTranslations(initLanguage)

   ...

   fun changeLanguage(language: String) {
      coroutinesScope.launch {
         translations = withContext(Dispatchers.IO) {
            database.getTranslations(language)
         }
      }
   }

   ...
}

重新分配翻译列表会导致观察 livedata 的片段继续观察旧的 livedata,所以我的策略是在更改语言时移除观察者并在片段中重新分配它。这似乎不是最好的解决方案,而且我也不确定如何确保在删除前一个观察者并重新创建数据之前已加载数据(我正在使用协程,所以我需要一种方法来进行回调当 livedata 被返回时)。

可能的解决方案

  1. 让数据库只返回一个 List 对象,而不是 livedata。然后我可以将它存储在可变的实时数据中。这并不理想,因为插入和更新不会自动反映在返回的列表中,因此每次更改特定语言的翻译列表时,我都必须重新获取数据。
  2. 获取所有翻译,然后在每次语言更改时过滤它们。一旦语言列表变大,这将有点占用资源。

所以我的问题是:有没有更好的方法可以在语言更改后重新分配实时数据?或者更确切地说,是否有一种可接受的方式让片段知道这种重新分配?

【问题讨论】:

    标签: android-fragments kotlin android-room android-lifecycle kotlin-coroutines


    【解决方案1】:

    您可以为该语言再创建一个LiveData,并使用switchMap 将其映射到翻译,例如:

    class translationViewmodel(private val database: TranslationDatabaseDao, initLanguage: String): ViewModel() {
      val language = MutableLiveData<String>("en")
      val translations = language.switchMap { language -> 
        database.getTranslations(language)
      }
      ...
    }
    

    现在,只需更改语言,翻译也会更新

    viewmodel.language.value = "es"
    

    【讨论】:

    • 谢谢,这很好用!我之前认为这是不可能的,因为数据库调用应该封装在协程启动块中。
    • @JJJacobs 欢迎您。返回 LiveData 的 Dao 方法已经在后台线程中获取它,因此从后台线程调用它们是没有意义的。
    猜你喜欢
    • 2021-01-04
    • 2011-09-21
    • 2021-02-25
    • 1970-01-01
    • 2021-03-28
    • 1970-01-01
    • 1970-01-01
    • 2014-01-27
    • 2011-05-10
    相关资源
    最近更新 更多