Lerex
Lerex

Reputation: 343

Flutter Hive with ChangeNotifierProvider

So I wanted to use Hive for storing notes in a Calendar app but I am stuggling so much with implementing Hive and a ChangeNotifierProvider together . If anyone has an idea on what to do I would like to see it.

Here is my code until now :

    @HiveType(typeId: 0)
class EventsBox extends HiveObject {
  EventsBox({required this.date, required this.eventsList});
  @HiveField(0)
  DateTime date;
  @HiveField(1)
  List<CleanCalendarEvent> eventsList;
}

And here is the FutureProvider that is needed :

final hiveProvider = FutureProvider<HiveDB>((_) => HiveDB.create());

class HiveDB {
  var _events;

  HiveDB._create() {}

  static Future<HiveDB> create() async {
    final component = HiveDB._create();
    await component._init();
    return component;
  }

  _init() async {
    Hive.registerAdapter(EventsBoxAdapter());
    this._events = await Hive.openBox<EventsBox>('events');
  }

  storeEvent(EventsBox eventsMap) {
    this._events.put('events', eventsMap);
  }

  EventsBox getEvents() {
    return this._events.get('events');
  }
}

I want to use ChangeNotifierProvider and not FutureProvider

Upvotes: 2

Views: 1238

Answers (1)

Kwame Opare Asiedu
Kwame Opare Asiedu

Reputation: 2345

The goal of the provider framework is to inject dependencies into your app without recreating them all the time. In your example, you have your HiveDB class which is what you want to inject into your app for various other widgets to use it.

IMO, the general approach of "providing" dependencies is:

  1. Create dependency instances outside the app (Typically in the main() function)
  2. Create a provider which injects this dependency object
  3. Wrap your MaterialApp with the provider
  4. Supply your dependency object into the provider wrapper
  5. Use the Provider<DependencyClass>.of(context) to access your dependency wherever you need it in your app.

Let's see how this applies to your code:

1. Setup your Hive models and HiveDB

lib/models/event_box.dart

@HiveType(typeId: 0)
class EventsBox extends HiveObject {
  @HiveField(0)
  DateTime date;

  @HiveField(1)
  List<CleanCalendarEvent> eventsList;

  EventsBox({
    required this.date, 
    required this.eventsList,
  });
}

lib/models/hive_db.dart

class HiveDB {
  var _events;

  HiveDB._create() {}

  static Future<HiveDB> create() async {
    final component = HiveDB._create();
    await component._init();
    return component;
  }

  _init() async {
    Hive.registerAdapter(EventsBoxAdapter());
    this._events = await Hive.openBox<EventsBox>('events');
  }

  storeEvent(EventsBox eventsMap) {
    this._events.put('events', eventsMap);
  }

  EventsBox getEvents() {
    return this._events.get('events');
  }
}

In this case, you want to "provide" (or inject) an instance of HiveDB to your app.

2. Create a provider for your HiveDB instance

lib/models/hive_db_provider.dart

class HiveDbProvider extends StatelessWidget {
  final HiveDB db;
  final Widget child;

  const HiveDbProvider({
    Key? key,
    required this.db,
    required this.child,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<HiveDB>.value(
      value: db,
      child: Consumer<AppCache>(
        builder: (context, db, _) {
          return child;
        },
      ),
    );
  }
}

3. Create HiveDB instance in main()

lib/main.dart

void main() async {
  final HiveDB db = await HiveDB.create();

  runApp(
    MyApp(db: db)
  );
}

...

4. Inject the HiveDB instance using the provider

lib/main.dart

...

class MyApp extends StatelessWidget {
  final HiveDB db;

  const PayBuddy({
    Key? key,
    required this.db,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return HiveDbProvider(
      db: db,
      child: CacheProvider(
        cache: cache,
        child: MaterialApp(
          ...
        ),
      ),
    );
  }
}

5. Access "provided" instance using Provider anywhere in your app

lib/pages/some_screen.dart

import "package:provider/provider.dart";
...

class SomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Access HiveDB instance
    final hiveDb = Provider<HiveDB>.of(context);

    ...
  }
}

Conclusion

The sample uses the Provider package which simplifies using provider usage in Flutter.

Upvotes: 3

Related Questions