Hydrated Bloc
A Bloc subclass that automatically persists its state to HydratedStorage on every emit and restores it the next time the Bloc is instantiated.
Setup
Assign the storage backend once at app startup before any HydratedBloc is created:
class App : Application() {
override fun onCreate() {
super.onCreate()
HydratedBloc.storage = SharedPreferencesStorage(this)
}
}Usage
@Serializable
data class CounterState(val count: Int = 0)
class CounterBloc : HydratedBloc<CounterState, CounterEvent>(
initialState = CounterState(),
serializer = CounterState.serializer(),
) {
init {
on<CounterEvent.Increment> { _, emit -> emit(state.copy(count = state.count + 1)) }
on<CounterEvent.Decrement> { _, emit -> emit(state.copy(count = state.count - 1)) }
}
}The count now survives app restarts with no extra code.
Storage key
Defaults to the class simple name (e.g. "CounterBloc"). Override for a stable, refactor-proof key:
override val storageKey get() = "counter_v2"Resetting state
| Method | Storage | In-memory state | Use case |
|---|---|---|---|
| clearStoredState | Deleted | Unchanged | Wipe storage; visible next launch |
| resetToInitialState | Deleted + re-written with initialState | Set immediately | Instant full reset |
Custom storage (e.g. for tests)
val bloc = CounterBloc(storage = InMemoryStorage())Parameters
Fallback used when no persisted data is found.
kotlinx.serialization serializer for S. Use MyState.serializer() (generated by the @Serializable annotation).
Storage backend. Defaults to HydratedBloc.storage.
Type Parameters
State type — must be annotated with @Serializable.
Event type.
Constructors
Properties
Hot SharedFlow of errors surfaced via addError().
Hot stream of every dispatched event, in arrival order.
The key under which this Bloc's state is persisted. Resolved at construction time to avoid the leaking-this trap with open val.
Functions
Signals an error without encoding it into the state type. Broadcasts to errorsFlow, then calls onError and BlocObserver.onError.
Deletes the persisted state without changing the current in-memory state. The next app launch will start from initialState.
Called when close completes. Cancel any background coroutines here. Always call super.onClose() to forward to BlocObserver.onClose.
Called whenever addError is invoked. Always call super.onError(error) to forward to BlocObserver.onError.
Called immediately before an event is dispatched to its handler. Always call super.onEvent(event) to forward to BlocObserver.onEvent.
Called after a synchronous emit that has an active event context. Always call super.onTransition(transition) to forward to BlocObserver.onTransition.
Deletes the persisted state and immediately emits initialState, resetting the UI right now without restarting the app.