Ofir Bar
02/19/2020, 4:28 PMreturnedExpertiseFields inside a ViewModel.
I want to initialize this list using a query to Room.
returnedExpertiseFields gets returned before it is initialized with values from Room, as in the code below:
fun getExpertiseFieldsById(expertiseFieldsIds: IntArray) : List<ExpertiseField>{
var returnedExpertiseFields = listOf<ExpertiseField>()
viewModelScope.launch {
returnedExpertiseFields = mExpertiseFieldFieldsRepository.getExpertiseFieldsFromDatabaseById(expertiseFieldsIds)
}
return returnedExpertiseFields
}
returnedExpertiseFields will return an empty list of ExpertiseField .
What can I do to make sure I always wait to Room query to be returned? I thought calling launch is synchronous?
(If you need my repository code I will post it, I just thought it might not be necessary)
Also, If any of you have any tips for debugging when using coroutines I will be glad to hear. I initially tought my Room query is broken. After long debugging I realized I am jumping between breakpoints rather them skipping them.Oleg Siboglov
02/19/2020, 4:43 PMfun getExpertiseFieldsById(expertiseFieldsIds: IntArray) : List<ExpertiseField> = withContext(<http://Dispatches.IO|Dispatches.IO>) {
mExpertiseFieldFieldsRepository.getExpertiseFieldsFromDatabaseById(expertiseFieldsIds)
}
Then you would call this method like so.
fun someMethod() {
viewModelScope.lauch {
val returnedExpertiseFields = getExpertiseFieldsById(ids)
// do something with the fields
}
}Brian
02/19/2020, 4:44 PMLiveData in the view model and observing that? something like:
val expertiseFields = MutableLiveData<List<ExpertiseField>>()
fun getExpertiseFieldsById(expertiseFieldsIds: IntArray) {
viewModelScope.launch {
expertiseFields.postValue(mExpertiseFieldFieldsRepository.getExpertiseFieldsFromDatabaseById(expertiseFieldsIds))
}
}
and then, from your activity or fragment:
// ... inside on onCreate or onViewCreated, for example
yourViewModel.expertiseFields.observe(this, { expertiseFields ->
// expertiseFields is your list
})Ofir Bar
02/19/2020, 4:51 PMOfir Bar
02/19/2020, 4:52 PMBrian
02/19/2020, 4:54 PMviewModelScopeOleg Siboglov
02/19/2020, 4:55 PM<http://Dispatchers.IO|Dispatchers.IO>?Oleg Siboglov
02/19/2020, 4:56 PMOfir Bar
02/19/2020, 4:57 PMOfir Bar
02/19/2020, 5:00 PMprivate fun someMethod(expertiseFieldsIds: IntArray) : List<ExpertiseField>{
viewModelScope.launch {
withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
mExpertiseFieldFieldsRepository.getExpertiseFieldsFromDatabaseById(expertiseFieldsIds)
}
}
}
How can I return value from an IO context?Oleg Siboglov
02/19/2020, 5:02 PMviewModelScope.launch {
returnedExpertiseFields = mExpertiseFieldFieldsRepository.getExpertiseFieldsFromDatabaseById(expertiseFieldsIds)
}
launch here is consuming an exception that Room would throw warning you about running a query on the main thread.Oleg Siboglov
02/19/2020, 5:07 PMfun someMethod() {
viewModelScope.launch {
val ids = getIds()
val fields = withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
mExpertiseFieldFieldsRepository.getExpertiseFieldsFromDatabaseById(ids)
}
//do something with fields
}
}Ofir Bar
02/19/2020, 5:15 PMOleg Siboglov
02/19/2020, 5:24 PMViewModel and instead use MVP, so I don’t know all the capabilities of ViewModel. However heres an example where view is a reference to your UI.
fun loadFields() {
CoroutineScope(Dispatchers.Main).launch {
val ids = getIds()
val fields = withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
mExpertiseFieldFieldsRepository.getExpertiseFieldsFromDatabaseById(ids)
}
// This coroutine is suspended until the room query completes. When it does complete, this coroutine is resumed and you can update the UI since you are back to using Dispatchers.Main
view.updateAdapterWithFields(fields)
}
}Oleg Siboglov
02/19/2020, 5:28 PMRoom and ViewModel- https://codelabs.developers.google.com/codelabs/kotlin-coroutines/#2