Background
I have my app setup as hexagonal architecture, with the UI (App), Domain and Database (Room) as separate modules. Upon pressing a button in the UI, user input data is being saved in the room database. If the Room database throws a SQLiteConstraintException
meaning the key already exists in the DB, I would like to query the user whether or not to overwrite the data.
My Idea
I'm new to android/kotlin development, but how I would imagine this to work is I would have an event which would trigger a UI AlertDialog. I would raise this event in the DB module, and if the alert dialog is accepted, a callback would run the save method in my Room DAO which would overwrite the data.
The Problems
- I tried to find some documentation about events in Kotlin but came up empty. Maybe im not using the right terms but "events" don't seem to be a recognized thing in Kotlin.
- The DB module does not see the UI module, so a dialog cannot be created directly from DB. This is why I would like to use an event in the first place.
- Because Room is asynchronous, I am running the save method in a
Dispatchers.IO
coroutine, and as far as I know its not possible to create UI fragments (like dialogs) in an IO coroutine. So far I've skirted this problem by usingthis@MyActivity.runOnUiThread
but that feels very hacky.
What I've Tried
GlobalScope.launch(Dispatchers.IO) {
val result = data.save(force = false)
when (result) {
false -> {
this@DataSaverActivity.runOnUiThread {
GenericDialogs(this@DataSaverActivity)
.confirmDialog(
onAccept = {data.save(force = true)},
onReject = {println("dialog rejected")})
}
}
true -> println("Successfully saved")
}
}
So heres my hackjob of a first attempt which does work but im not happy with it at all. This code is in a method in my viewmodel, which is called when the save button is pressed.
data.save()
returns false if the Dao raises a SQLiteConstraintException
and true otherwise. the force
argument determines whether the data is saved using onConflict = ABORT
or onClonflict = REPLACE
. Basically if force
is true, it will overwrite pre-existing keys, and if false it will throw the SQL error. On a failed save, a dialog will then be created and supplied with a callback that resaves with forced overwrite.
I would much prefer to use Events or something equivalent in Kotlin to clean up the logic.