首页 > 解决方案 > 在 initState 中调用提供者上下文

问题描述

我想在 initState 方法中从数据库中获取一个值。因此,我尝试通过使用 Provider.of(context) 方法调用函数来访问该值。但是,我收到以下错误:

 E/flutter ( 6424): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: Error: Could not find the correct Provider<RestaurantTimings> above this MyApp Widget
E/flutter ( 6424):
E/flutter ( 6424): This likely happens because you used a `BuildContext` that does not include the provider
E/flutter ( 6424): of your choice. There are a few common scenarios:
E/flutter ( 6424):
E/flutter ( 6424): - The provider you are trying to read is in a different route.
E/flutter ( 6424):
E/flutter ( 6424):   Providers are "scoped". So if you insert of provider inside a route, then
E/flutter ( 6424):   other routes will not be able to access that provider.
E/flutter ( 6424):
E/flutter ( 6424): - You used a `BuildContext` that is an ancestor of the provider you are trying to read.
E/flutter ( 6424):
E/flutter ( 6424):   Make sure that MyApp is under your MultiProvider/Provider<RestaurantTimings>.
E/flutter ( 6424):   This usually happen when you are creating a provider and trying to read it immediately.
E/flutter ( 6424):
E/flutter ( 6424):   For example, instead of:
E/flutter ( 6424):   For example, instead of:
E/flutter ( 6424):
E/flutter ( 6424):   ```
E/flutter ( 6424):   Widget build(BuildContext context) {
E/flutter ( 6424):     return Provider<Example>(
E/flutter ( 6424):       create: (_) => Example(),
E/flutter ( 6424):       // Will throw a ProviderNotFoundError, because `context` is associated
E/flutter ( 6424):       // to the widget that is the parent of `Provider<Example>`
E/flutter ( 6424):       child: Text(context.watch<Example>()),
E/flutter ( 6424):     ),
E/flutter ( 6424):   }
E/flutter ( 6424):   ```
E/flutter ( 6424):
E/flutter ( 6424):   consider using `builder` like so:
E/flutter ( 6424):
E/flutter ( 6424):   ```
E/flutter ( 6424):   Widget build(BuildContext context) {
E/flutter ( 6424):     return Provider<Example>(
E/flutter ( 6424):       create: (_) => Example(),
E/flutter ( 6424):       // we use `builder` to obtain a new `BuildContext` that has access to the provider
E/flutter ( 6424):       builder: (context) {
E/flutter ( 6424):         // No longer throws
E/flutter ( 6424):         return Text(context.watch<Example>()),
E/flutter ( 6424):       }
E/flutter ( 6424):     ),
E/flutter ( 6424):   }

这是我的代码:

Future<void> main() async { 
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  var _isLoading = false;
  var isOpen = false; 
  ClosingOpeningHours _timing;
  
  void initState(){ 
    super.initState();
    _getTimingOrClosing();
  }
  
  _getTimingOrClosing() async{ 
    _timing =  await Provider.of<RestaurantTimings>(context, listen: false)
                                   .fetchTiming();
    print('Start close in main ' + _timing.startClose); 
  }
   Future<void> _initPackageInfo() async {
           setState(() {
  _isLoading = true;
  });
    print('Inside initPackageInfo'); 
    final info = await PackageInfo.fromPlatform();
    setState(() {
      _packageInfo = info;
    });
  }
 
   @override
  Widget build(BuildContext context) {
   
    return !(_isLoading)?MultiProvider(
      providers: [
       ChangeNotifierProvider(
          create: (_) => Auth(),
        ),
        ChangeNotifierProxyProvider<Auth, Products>(
          create:null,
          update:(ctx,auth, previousProducts) => Products(auth.token, 
          
        auth.userId)), 
         
        ChangeNotifierProvider(
          create: (_) => Cart(),
        ),
        
        ChangeNotifierProvider(
          create: (_) => ColorChanger(),
        ),
          ChangeNotifierProxyProvider<Auth,RestaurantTimings>(
          create:null,
         update:(ctx,auth, previousTimings) => RestaurantTimings(auth.token)),
    ],

    //The consumer ensures that the material app gets built whenever Auth object changes
        child: Consumer<Auth>(builder: (ctx, auth, _) => 
          MaterialApp( 
        navigatorKey: navigatorKey,    
        title: 'MyApp',
        theme: ThemeData(
           textTheme: Theme.of(context).textTheme.apply(
            bodyColor: Colors.black,
            displayColor: Colors.black,
            ),
          primaryColor:  Colors.white,
          accentColor:  Color(0xFFF2AD18),
          fontFamily: 'Muli',
        ),
        home:      
             auth.isAuth && !isopen ? StoreTimings(): auth.isAuth && isopen?
        CategoriesScreen()
         : FutureBuilder(
                      future: auth.tryAutoLogin(),
                      builder: (ctx, authResultSnapshot) =>
                          authResultSnapshot.connectionState ==
                                  ConnectionState.waiting
                              ?  Center(
                                    child: Loading(),
                                )
                              : LoginPage(),
        ),
        routes: {
          ProductDetailScreen.routeName:(ctx) => ProductDetailScreen(),
        }
      ),
        ) 
    ):Center(child:Loading());
  }
}

引发此错误的具体代码是:

_timing =  await Provider.of<RestaurantTimings>(context, listen: false)
                                   .fetchTiming();

如果您查看我的代码,您会看到我已经RestaurantTiming在 multiprovider 中列出。我真的需要在主 UI 构建之前运行它。

标签: flutterdart

解决方案


我不确定它是否有效,但你介意这样尝试吗

  @override
  void initState() {
    super.initState();
    SchedulerBinding.instance.addPostFrameCallback((_) async {
      _getTimingOrClosing();
    });
  }

推荐阅读