"Refresh" 房间数据库提供的 LiveData 的最佳方式
Best Way to "Refresh" LiveData Provided by Room Database
我目前正在使用 Room 来存储单词翻译列表,并 return 将查询作为 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)
}
}
}
...
}
重新分配翻译列表会导致观察实时数据的片段继续观察旧的实时数据,所以我的策略是在更改语言时删除观察者并在片段中重新分配它。这似乎不是这里最好的解决方案,而且我也不确定如何确保在删除以前的观察者并重新创建它之前已加载数据(我正在使用协程,所以我需要一种方法来进行回调当实时数据被 returned 时)。
可能的解决方案
- 让数据库 return 只是一个 List 对象,而不是 livedata。然后我可以将它存储在可变的实时数据中。这并不理想,因为插入和更新不会自动反映在 returned 列表中,因此每次更改特定语言的翻译列表时我都必须重新获取数据。
- 获取所有翻译,然后在每次语言更改时对其进行过滤。一旦语言列表变大,这会占用一些资源。
所以我的问题是:有没有更好的方法可以在语言更改后重新分配实时数据?或者更确切地说,是否有一种可接受的方式让片段知道这种重新分配?
您可以为该语言再创建一个 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"
我目前正在使用 Room 来存储单词翻译列表,并 return 将查询作为 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)
}
}
}
...
}
重新分配翻译列表会导致观察实时数据的片段继续观察旧的实时数据,所以我的策略是在更改语言时删除观察者并在片段中重新分配它。这似乎不是这里最好的解决方案,而且我也不确定如何确保在删除以前的观察者并重新创建它之前已加载数据(我正在使用协程,所以我需要一种方法来进行回调当实时数据被 returned 时)。
可能的解决方案
- 让数据库 return 只是一个 List 对象,而不是 livedata。然后我可以将它存储在可变的实时数据中。这并不理想,因为插入和更新不会自动反映在 returned 列表中,因此每次更改特定语言的翻译列表时我都必须重新获取数据。
- 获取所有翻译,然后在每次语言更改时对其进行过滤。一旦语言列表变大,这会占用一些资源。
所以我的问题是:有没有更好的方法可以在语言更改后重新分配实时数据?或者更确切地说,是否有一种可接受的方式让片段知道这种重新分配?
您可以为该语言再创建一个 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"