Vector State¶
Vector recommends using immutable Kotlin Data Classes to represent your UI Model classes. Such classes should implement the VectorState
interface, because the VectorViewModel
class is generic on a subtype of this interface.
It is recommended to keep your state classes immutable, otherwise you risk your UI model getting into inconsistent states when there are multiple sources producing state updates concurrently.
Example¶
data class ProfilePageState( val user: User, val isLoading: Boolean, val isError: Boolean ): VectorState
Using a Data Class provides the benefit of the automatically generated copy()
method. It allows you to mutate the state very easily, you just need to provide the values that have actually changed, and the others will be kept the same. For example, if the User Profile page in the above example starts in the Loading
state, the initial state model would look like this:
val initialState = ProfilePageState( user = cachedUser, isLoading = true, isError = false )
When the loading completes, the state can be mutated easily like this:
val newState = initialState.copy( user = userRetrievedFromNetwork, isLoading = false )
Since the isError
variable value remains the same (false), we do not need to supply it in the copy
method.
Sealed Class based Model Classes¶
A great way to represent all possible states a screen can be in is using Kotlin's Sealed Classes.
Continuing the profile page example, suppose we want to show a different types of information based on whether the user is a premium user or not. We can do it this way:
sealed class ProfilePageState: VectorState { data class PremiumProfilePage( val user: User, val accountPerks: List<Perks>, val isLoading: Boolean, val isError: Boolean ): ProfilePageState() data class StandardProfilePage( val user: User, val isLoading: Boolean, val isError: Boolean ): ProfilePageState() }
This allows you to separate similar, but related states of a screen. It increases verbosity though, and you lose direct access to convenient data class methods, unless you type cast the state object into one of its subclasses.
Persistable state¶
Kotlin Extensions for Android have the ability to automatically generate Parcelable
implementations of data classes with the @Parcelize
annotation. This can be leveraged to easily persist state classes when needed.
@Parcelize data class ProfilePageState( ... ): Parcelable
When needed, this state can be directly put as a Serializable
into a SavedInstanceState
bundle or a SavedStateHandle
in a ViewModel.
Automatic State Restoration¶
If you use the lazy ViewModel delegates shipped with Vector, you must ensure that either:
- Your state class has default values for every property, or
- Your ViewModel class implements the
VectorViewModelFactory
interface along with itsinitialState
method
This is to ensure that we can create an instance of your state class automatically.