Home > database >  Proper way of using sealed interface in kotlin
Proper way of using sealed interface in kotlin

Time:11-25

I am totally new in sealed Interface in kotlin. I am trying to state management through sealed in android kotlin. My main goal is when I used the object of sealed i don't want to inherit all child. I am not sure correctly is that sealed interface is right choice for me. All my code may be wrong, please correct if I am wrong Thanks.

sealed interface ConnectionUIState

sealed class BluetoothConnectionUIState {
    object Initial : BluetoothConnectionUIState()
    data class ScanningDevice(val storedDevice: SnapshotStateList<BluetoothDevice>? = null) : ConnectionUIState
}

I initialise the variable like this

var uiState by mutableStateOf<BluetoothConnectionUIState>(BluetoothConnectionUIState.Initial)
        private set

Now I am passing the uiState variable in the function and using when statement

when (uiState) {
        BluetoothConnectionUIState.ScanningDevice -> {
            xuz()
        }
    }

why when statement is giving error

'when' expression must be exhaustive, add necessary 'Initial' branch or 'else' branch instead

Also this line is also giving me error BluetoothConnectionUIState.ScanningDevice in when statement.

Error

Classifier 'ScanningDevice' does not have a companion object, and thus must be initialized here

If I am doing wrong here. Can you please elaborate of 2 point of this stack overflow. Thanks

UPDATE

I did some changes

sealed interface ConnectionUIState

sealed class BluetoothConnectionUIState {
    object Initial : ConnectionUIState
    data class ScanningDevice(val storedDevice: SnapshotStateList<BluetoothDevice>? = null) : BluetoothConnectionUIState()
}

I did success on when statement that it's not complaining about Initial

when (uiState) {
        is BluetoothConnectionUIState.ScanningDevice -> {
            BluetoothPairContent(viewModel, tryAgainAction, openSettingAction, scanDeviceList)
        }
    }

That is my goal, but another problem raised that it gives error in uiState initialise time

var uiState by mutableStateOf<BluetoothConnectionUIState>(BluetoothConnectionUIState.Initial)
        private set

Error

Type mismatch.
Required:
BluetoothConnectionUIState
Found:
BluetoothConnectionUIState.Initial

Again I am confused. Please guide me on this. Thanks

CodePudding user response:

(I think you worked it out but just in case - you need is in your when to check if something is a class. When comparing to an object you use equality, which can just be written as the value to match)

Working off your update:

// simplified for readability
sealed interface ConnectionUIState

sealed class BluetoothConnectionUIState {
    object Initial : ConnectionUIState
    data class ScanningDevice : BluetoothConnectionUIState()
}

You've got this object and class nested inside BluetoothConnectionUIState, which means their fully qualified names are things like BluetoothConnectionUIState.Initial. But you don't actually have to nest them, you can do this:

sealed class BluetoothConnectionUIState
object Initial : ConnectionUIState
data class ScanningDevice : BluetoothConnectionUIState()

Now Initial and ScanningDevice aren't nested inside BluetoothConnectionUIState, you just reference them directly. So what's the relationship between them now? Look at the constructors:

// subclass of BluetoothConnectionUIState
data class ScanningDevice : BluetoothConnectionUIState()

// implements the ConnectionUIState interface
object Initial : ConnectionUIState

Once you remove the nesting, you can see that Initial actually has no type relationship with the sealed class at all! It just happened to be located inside it. And that's why you can't put it in your mutableStateOf - it's not a BluetoothConnectionUIState.

It's also why you were getting the must be exhaustive error in your original when block - you only had a branch checking Initial, which isn't part of the sealed class anyway. It works when you check ScanningDevice, because that's the only member of the class - if uiState is a BluetoothConnectionUIState, it must be a ScanningDevice.


How you fix this is up to you - seems like you want those two things to be part of the same sealed class. Maybe you want ConnectionUIState to be the sealed class? Since that's what they both represent. And have BluetoothConnectionUIState be the interface that you can apply selectively to certain members of that sealed class?

sealed interface BluetoothConnectionUIState

sealed class ConnectionUIState {
    object Initial : ConnectionUIState()
    data class ScanningDevice : ConnectionUIState(), BluetoothConnectionUIState
}

This overview might be a helpful read too!

  • Related