Home > Software engineering >  How to get a message sent from View Model using a sealed class?
How to get a message sent from View Model using a sealed class?

Time:10-27

I have an app that uses Kotlin with an MVVM approach. My goal here is to send the state (SUCCESS, FAIL, ERROR, EXCEPTION.VM_INSERT...) from View Model to activity. In my activity, I observe the state and based on that I will inform the user about the state. The SUCCESS, FAIL, ERROR state works as expected, unfortunately, I struggle to find out how show in Activity the exception message send by EXCEPTION.VM_INSERT.

ViewModel State:

sealed class ViewModelState {

    sealed class EXCEPTION : ViewModelState() {
        class VM_INSERT(val exception: String) : ViewModelState()
        class VM_UPDATE(val exception: String) : ViewModelState()
        class VM_DELETE(val exception: String) : ViewModelState()
        class VM_QUERY(val exception: String) : ViewModelState()
    }
    
    object SUCCESS : ViewModelState()
    object FAIL : ViewModelState()
    object ERROR : ViewModelState()

}

ViewModel:

...
    private val _insertWordStatus = MutableLiveData<ViewModelState>()
    val insertWordStatus: LiveData<ViewModelState> = _insertWordStatus

    fun insertWord(word: Word) = viewModelScope.launch {

        try {
            val insertedRowId = repository.insertWord(word)

            if (insertedRowId > -1) {
                _insertWordStatus.value = ViewModelState.SUCCESS
            } else {
                _insertWordStatus.value = ViewModelState.FAIL
            }

        } catch (ex: Exception) {
            _insertWordStatus.value = ViewModelState.ERROR
            _insertWordStatus.value =
                ex.localizedMessage.toString()?.let { ViewModelState.EXCEPTION.VM_INSERT(it) }

        }
...

Activity:

...
        wordViewModel.insertWordStatus.observe(this, Observer { viewModelState ->

            if (viewModelState == ViewModelState.SUCCESS ) {

            } else if (viewModelState == ViewModelState.FAIL) {

            } else if (viewModelState == ViewModelState.ERROR) {

            } else {

            }

        })
...

CodePudding user response:

You forgot to make all the intended children of EXCEPTION subclasses of EXCEPTION. Also, you should move their shared property into the superclass so you take advantage of inheritance to, for example, log the error without having to check the specific type of EXCEPTION.

sealed class EXCEPTION(val exception: String) : ViewModelState() {
    class VM_INSERT(exception: String) : EXCEPTION(exception)
    class VM_UPDATE(exception: String) : EXCEPTION(exception)
    class VM_DELETE(exception: String) : EXCEPTION(exception)
    class VM_QUERY(exception: String) : EXCEPTION(exception)
}

In my opinion, you should refactor it as follows. I don't think the complexity of a sealed class is justified if every one of its children has identical class structure. That's really fighting against the basic principles of object oriented programming. Example:

class EXCEPTION(val exception: String, val type: EXCEPTION.Type) : ViewModelState() {
    enum class Type { VM_INSERT, VM_UPDATE, VM_DELETE, VM_QUERY }
}

By the way, you should look up how to use when statements in Kotlin. It is much cleaner than a chain of else ifs when they're all checking against the same argument. Example:

wordViewModel.insertWordStatus.observe(this) { viewModelState ->

    when(viewModelState) {
        ViewModelState.SUCCESS - > {

        } 
        ViewModelState.FAIL -> {

        } 
        ViewModelState.ERROR -> {

        } 
        ViewModelState.EXCEPTION -> {

        } 
    }

}
  • Related