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
VectorViewModelFactoryinterface along with itsinitialStatemethod
This is to ensure that we can create an instance of your state class automatically.