I often ask myself how to work with coroutines. Every time a button click or some other event comes up I start a coroutine to save or load data from/to a database or a rest api. I then have small functions like below.
In rare cases I get ConcurrentModificationExceptions if two or more coroutines write/read at the same time. I never had this problem with Java+RxJava. Now I only use Kotlin+Coroutines (no RxKotlin, no Flow, no LiveData). As a database I use Room.
Is there a way to hold a reference to something like a Coroutine-Container where I can just add Jobs to get them done one after another? Or how do you guys actually launch your coroutines?
fun loadAllDataForTheUserInterface() {
viewModelScope.launch {
val newData = dataBaseRepository.load(...)
fragment.draw(newData)
}
}
or
fun handleSaveClick(user: User) {
viewModelScope.launch {
val newUser = restApiRepository.uploadNewUser(user)
databaseRepository.save(newUser)
fragment.close()
}
}
My stacktrace
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:96)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:61)
at com.google.gson.Gson.toJson(Gson.java:704)
at com.google.gson.Gson.toJson(Gson.java:683)
at com.google.gson.Gson.toJson(Gson.java:638)
at com.google.gson.Gson.toJson(Gson.java:618)
at my.supercool.app.component.module.JsonModule.toJson(JsonModule.kt:12)
at my.supercool.app.data.database.MyRoomObjectConverter.fromObjectToJson(MyRoomObjectConverter.kt:29)
at my.supercool.app.data.database.MyRoomObjectConverter.fromSomeListToJson(MyRoomObjectConverter.kt:71)
at my.supercool.app.data.database.dao.SomeDao_Impl$1.bind(SomeDao_Impl.java:101)
at my.supercool.app.data.database.dao.SomeDao_Impl$1.bind(SomeDao_Impl.java:47)
at androidx.room.EntityInsertionAdapter.insertAndReturnId(EntityInsertionAdapter.java:113)
at my.supercool.app.data.database.dao.SomeDao_Impl$4.call(SomeDao_Impl.java:142)
at my.supercool.app.data.database.dao.SomeDao_Impl$4.call(SomeDao_Impl.java:137)
at androidx.room.CoroutinesRoom$Companion$execute$2.invokeSuspend(CoroutinesRoom.kt:61)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at androidx.room.TransactionExecutor$1.run(TransactionExecutor.java:47)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)