How to call an async method using ProxyProvider?

Issue

One of my services, UserService, has an async init method (as it calls Hive.openBox).

I need this initialization to complete in order to inject this dependency into ChatService.

main() {
  runApp(MultiProvider(
    providers: [
        Provider<Api>.value(value: Api()),
        ProxyProvider<Api, UserService>(update: (_, api, __) async {
          var service = UserService(api);
          await service.init();
          return service;
        }),
        ChangeNotifierProxyProvider<UserService, ChatService>(
          create: (_) => ChatService(),
          update: (_, userService, chatService) => chatService..userService = userService
        ),
      ],
      child: MyApp(),
  ));
}

Of course, attempting to make create async gives the following error because of the type mismatch:

The argument type 'Future<UserService> Function(BuildContext, Api, UserService)' can't be assigned to the parameter type 'UserService Function(BuildContext, Api, UserService)'.dart(argument_type_not_assignable)

How can I await this method using ProxyProvider?

Is get_it a better tool for what I’m trying to do?

EDIT AFTER REMI’S ANSWER

I’m using FutureProvider now but it’s still unclear how to feed the initialized UserService dependency into the next dependant ChatService when it’s immutable:

      providers: [
        Provider<Api>(create: (_) => Api()),
        FutureProvider<UserService>(
          lazy: false,
          create: (context) async {
            var service = UserService(Provider.of(context, listen: false));
            await service.init();
            return service;
          }
        ),
        ChangeNotifierProvider<ChatService>(
          create: (context) => ChatService(Provider.of<UserService>(context, listen: false)), // UserService is null
        )
      ],

UserService is null by the time create is called.

Using a ChangeNotifierProxyProvider‘s update that wouldn’t work either UserService is a constructor dependency.

Solution

You can use FutureProvider instead:

Provider<Api>(create: (_) => Api()),
FutureProvider<UserService>(
  create: (context) async {
    var service = UserService(Provider.of(context, listen: false));
    await service.init();
    return service;    
  },
),

You could also do:

void main() async {
  final service = UserService();
  await service.init();

  runApp(
    Provider.value(
      value: service,
    ),
  );
}

Answered By – Rémi Rousselet

Answer Checked By – Marilyn (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *