Home > OS >  In Flutter MaterialApp, using Provider inside LocaleResolutionCallback has an error
In Flutter MaterialApp, using Provider inside LocaleResolutionCallback has an error

Time:01-27

In my flutter project, I selected riverpod_hook for DI.

In order to change the language setting of the application according to the language setting of the mobile device, I wrote the code as follows.

// app.dart
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

class Application extends ConsumerWidget {
  const Application({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return MaterialApp(
      theme: defaultTheme,
      localizationsDelegates: Resource.localizationsDelegates,
      supportedLocales: Resource.supportedLocales,
      localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) {
        if (supportedLocales.any((element) => locale?.languageCode.contains(element.toString()) == true)) {
          ref.watch(localeCodeProvider.notifier).state = locale!.languageCode;
          return locale;
        }
        return const Locale('ko', '');
      },
      routes: {
        homePageRoutes: (_) => const HomePage(),
        detailPageRoutes: (_) => const DetailPage(),
      },
    );
  }
}

import 'package:hooks_riverpod/hooks_riverpod.dart';

final localeCodeProvider = StateProvider<String>((ref) => 'en');

When I run this code, this error was occurred.

E/flutter ( 3747): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: Tried to modify a provider while the widget tree was building.
E/flutter ( 3747): If you are encountering this error, chances are you tried to modify a provider
E/flutter ( 3747): in a widget life-cycle, such as but not limited to:
E/flutter ( 3747): - build
E/flutter ( 3747): - initState
E/flutter ( 3747): - dispose
E/flutter ( 3747): - didUpdateWidget
E/flutter ( 3747): - didChangeDepedencies
E/flutter ( 3747): 
E/flutter ( 3747): Modifying a provider inside those life-cycles is not allowed, as it could
E/flutter ( 3747): lead to an inconsistent UI state. For example, two widgets could listen to the
E/flutter ( 3747): same provider, but incorrectly receive different states.
E/flutter ( 3747): 
E/flutter ( 3747): 
E/flutter ( 3747): To fix this problem, you have one of two solutions:
E/flutter ( 3747): - (preferred) Move the logic for modifying your provider outside of a widget
E/flutter ( 3747):   life-cycle. For example, maybe you could update your provider inside a button's
E/flutter ( 3747):   onPressed instead.
E/flutter ( 3747): 
E/flutter ( 3747): - Delay your modification, such as by encasuplating the modification
E/flutter ( 3747):   in a `Future(() {...})`.
E/flutter ( 3747):   This will perform your upddate after the widget tree is done building.

I can see from the error message that the error occurred because the provider watch was used inside the build function.

However, I unwillingly need to utilize that localeResolutionCallback attribute because I want to set the language setting value of the mobile device and set the language across the application.

In this situation, could I get an appropriate solution on how to use the provider?

CodePudding user response:

Try if calling WidgetsBinding.instance.addPostFrameCallback would work, somethign like this:

if (supportedLocales.any((element) => locale?.languageCode.contains(element.toString()) == true)) {
WidgetsBinding.instance.addPostFrameCallback((_) {          
    ref.watch(localeCodeProvider.notifier).state = locale!.languageCode;
});
          return locale;
        }
```

What it does - it allows your build to complete; and then changes the provider - which will most likely call another build.
  • Related