I'm currently using Room to store a list of translations of words, and returning queries as LiveData to monitor insertions and updates. I run into problems however when I need to re-fetch the translations for a different source language (my current strategy is to re-assign the livedata to the result from the room query).
I fetch languages to translate and translations for a specific language using the below SQL queries
@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>>
...
}
which I call when instantiating a viewmodel, and again when the user changes the language (see changeLanguage(...)
below).
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)
}
}
}
...
}
Re-assigning the list of translations causes the fragment observing the livedata to keep observing the old livedata, so my strategy has been to remove the observer and reassign it in the fragment when changing languages. This doesn't seem like the best solution here, and I'm also not sure how to ensure the data has been loaded before removing the previous observer and recreating it (I'm using coroutines so I would need a way to have a callback when the livedata has been returned).
So my question is: Is there a better way that re-assigning the livedata after a language change? Or rather, is there an accepted way to have the fragment be aware of this re-assignment?
You can create one more LiveData
for the language, and use switchMap to map it to the translations, like:
class translationViewmodel(private val database: TranslationDatabaseDao, initLanguage: String): ViewModel() {
val language = MutableLiveData<String>("en")
val translations = language.switchMap { language ->
database.getTranslations(language)
}
...
}
Now, just change the language and translations will be updated too
viewmodel.language.value = "es"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With