0

Rather than calling some async function to get document directory and initialize hive database inside main function, I want to keep things as abstract as possible. I want to implement Hive.init(..) inside a provider service and calling that service during initState() method. In this way my main method does not care or even does not know what database I am using, rather than calling the provider service. The implementation should be like this.

service.dart

class Service extends ChangeNotifier {
  ....

  Future<void> init() async {
    Directory dir = await getExternalStorageDirectory();
    Hive.init(dir.path);

 ....

view.dart

class MyPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (BuildContext context) => Service(),
      child: _MyPageContent(),
    );
  }
}

.....

class _MyPageContent extends StatefulWidget {
  @override
  __MyPageContentState createState() => __MyPageContentState();
}

class __MyPageContentState extends State<_MyPageContent> {
  @override
  void initState() {
    super.initState();
    Provider.of<Service>(context, listen: false).init();
  }
  ....
....

However, this is not working. The error I am getting as

HiveError (HiveError: You need to initialize Hive or provide a path to store the box.)

The reason may be Service.init() method, being an async one, is getting called inside initState() by the time build method performs it's task. So is there any way to fix this ?

padaleiana
  • 955
  • 1
  • 14
  • 23
  • the parent uses the Service and you are initializing it from a child? initialize service inside the `MyPage` – Yadu Jul 29 '20 at 06:42

2 Answers2

0

Give the service a function to execute when it loads the Hive


class Service extends ChangeNotifier {
  Future<void> init(Function onDoneInitializing) async {
    Directory dir = await getExternalStorageDirectory();
    Hive.init(dir.path);
    onDoneInitializing();
  }
}

change the content according to the state set by the function you gave to the Service.init

class MyPage extends StatefulWidget {
  @override
  _MyPageState createState() => _MyPageState();
}

class _MyPageState extends State<MyPage> {
  bool doneInitializing = false;
  Service _service;

  @override
  void initState() {
    _service = Service();
    _service.init(() {
      setState(() {
        doneInitializing = true;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return doneInitializing
        ? ChangeNotifierProvider(
      create: (BuildContext context) => _service,
      child: _MyPageContent(),
    )
        : CircularProgressIndicator();
  }
}

Yadu
  • 2,979
  • 2
  • 12
  • 27
0

I changed my state class and it seems to be working.

class __MyPageContentState extends State<_MyPageContent> {

  bool _init = false;

  @override
  void initState() {
    super.initState();
    Provider.of<Service>(context, listen: false).init()
    .then((_) => setState(() => _init = true));
  }
  
  @override
  Widget build(BuildContext context) {
    if(_init)
      return MyPreciousWidget(...);
    return CircularProgressIndicator();
  }
....