An extension to package:bloc which automatically persists and restores bloc and cubit states. Built to work with package:bloc.

Learn more at bloclibrary.dev!

hydrated_bloc exports a Storage interface which means it can work with any storage provider. Out of the box, it comes with its own implementation: HydratedStorage .

HydratedStorage is built on top of hive for a platform-agnostic, performant storage layer. See the complete example for more details.

Setup HydratedStorage #

void main() async { WidgetsFlutterBinding.ensureInitialized(); HydratedBloc.storage = await HydratedStorage.build(); runApp(App()); }

Create a HydratedCubit #

class CounterCubit extends HydratedCubit<int> { CounterCubit() : super(0); void increment() => emit(state + 1); @override int fromJson(Map<String, dynamic> json) => json['value'] as int; @override Map<String, int> toJson(int state) => { 'value': state }; }

Create a HydratedBloc #

enum CounterEvent { increment } class CounterBloc extends HydratedBloc<CounterEvent, int> { CounterBloc() : super(0); @override Stream<int> mapEventToState(CounterEvent event) async* { switch (event) { case CounterEvent.increment: yield state + 1; break; } } @override int fromJson(Map<String, dynamic> json) => json['value'] as int; @override Map<String, int> toJson(int state) => { 'value': state }; }

Now the CounterCubit and CounterBloc will automatically persist/restore their state. We can increment the counter value, hot restart, kill the app, etc... and the previous state will be retained.

class CounterCubit extends Cubit<int> with HydratedMixin { CounterCubit() : super(0) { hydrate(); } void increment() => emit(state + 1); @override int fromJson(Map<String, dynamic> json) => json['value'] as int; @override Map<String, int> toJson(int state) => { 'value': state }; }

Custom Storage Directory #

By default, all data is written to temporary storage which means it can be wiped by the operating system at any point in time.

An optional storageDirectory can be provided to override the default temporary storage directory:

HydratedBloc.storage = await HydratedStorage.build( storageDirectory: await getApplicationDocumentsDirectory(), );

Custom Hydrated Storage #

If the default HydratedStorage doesn't meet your needs, you can always implement a custom Storage by simply implementing the Storage interface and initializing HydratedBloc with the custom Storage .

// my_hydrated_storage.dart class MyHydratedStorage implements Storage { @override dynamic read(String key) { // TODO: implement read } @override Future<void> write(String key, dynamic value) async { // TODO: implement write } @override Future<void> delete(String key) async { // TODO: implement delete } @override Future<void> clear() async { // TODO: implement clear } }