0

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 using this@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.

Olli
  • 183
  • 2
  • 11

1 Answers1

0

I think it's an exception handing issue. I would do it like this:

  • Pressing the button in the UI to save the input data, call a use case "saveData".

  • Inside the use case, you catch the infraestructue exception thrown by the SQL adapter, you translate it into a custom busines exception: "DataAlreadyExistsException", and you throw it to the UI.

  • The UI catches the "DataAlreadyExistsException" and handles it, showing the user the dialog box that ask for overwriting the data.

  • If the user press the button for overwriting, will call another use case: "overwriteData".

  • If the user press the button for not overwriting, do nothing.

choquero70
  • 3,332
  • 2
  • 24
  • 40