ProviderNotFoundException(错误:使用layoutBuilder在此SchedulingPage小部件上方找不到正确的Provider <LayoutData>

时间:2020-04-12 08:23:51

标签: flutter flutter-provider

我遇到了providerNotFoundException,我怀疑下面的代码中存在上下文不匹配的情况,但是我很难看到它。据我了解,当在同一构建方法中执行.of方法时,BuilderContext会出现问题,但在这种情况下我看不到这种情况。如下面的代码所示,某些Provider.of方法可以正常工作,但是一旦调用SchedulingPage,Provider.of方法就不再起作用。

这是什么问题?

编辑:我更新为使用下面的完整代码: 这是完整的错误:ProviderNotFoundException(错误:在此LoginForm小部件上方找不到正确的提供程序

void main() {
  runApp(
    Home(),
  );
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        // ChangeNotifierProvider(create: (context) => CalendarData()),
        ChangeNotifierProvider(create: (context) => LayoutData()),
      ],
      child: MyApp(),
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SafeArea(
        child: LayoutBuilder(
            builder: (BuildContext context, BoxConstraints constraints) {
          print("constraints: $constraints");
          Size mediaSize = MediaQuery.of(context).size;
          double safeAreaSize = mediaSize.height - constraints.maxHeight;
          Provider.of<LayoutData>(context).safeAreaDiff = safeAreaSize;
          Provider.of<LayoutData>(context).safeArea = constraints;
          Provider.of<LayoutData>(context).mediaArea = mediaSize;
          var test = Provider.of<LayoutData>(context).mediaArea.width;
          print(test);  // this works

          return Scaffold(body: LoginScreen());
        }),
      ),
    );
  }
}

    class LoginScreen extends StatelessWidget {
      const LoginScreen({Key key}) : super(key: key);

      @override
      Widget build(BuildContext context) {
        double test = Provider.of<LayoutData>(context).mediaArea.width;
        print("test: $test");  // this works
        return LoginForm();
      }
    }

    class LoginForm extends StatefulWidget {
      LoginForm({Key key}) : super(key: key);

      @override
      _LoginFormState createState() => _LoginFormState();
    }

    class _LoginFormState extends State<LoginForm> {
      @override
      Widget build(BuildContext context) {
        double width = Provider.of<LayoutData>(context).mediaArea.width; // The code fails here
        print('width: $width');
        return Text("this is where it fails ^^^^^^^^");
      }
    }

    class LayoutData with ChangeNotifier {
      double safeAreaDiff = 0.0;
      BoxConstraints safeArea;
      Size mediaArea;

      LayoutData() {
        initializeApp();
      }

      void initializeApp() {
        print("layout initialized");
      }
    }

3 个答案:

答案 0 :(得分:1)

您不能在您创建的同一类中访问提供程序。那必须是父窗口小部件。

void main() {
  runApp(Home());
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => CalendarData()),
        ChangeNotifierProvider(create: (context) => LayoutData()),
      ],
      child: MyApp(),
    );
  }
}


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SafeArea(
        child: LayoutBuilder(
            builder: (BuildContext context, BoxConstraints constraints) {
          print("constraints: $constraints");
          Size mediaSize = MediaQuery.of(context).size;
          double safeAreaSize =
              mediaSize.height - constraints.maxHeight; // works
          Provider.of<LayoutData>(context).safeAreaDiff =
              safeAreaSize; // works
          Provider.of<LayoutData>(context).safeArea = constraints; // works
          Provider.of<LayoutData>(context).mediaArea = mediaSize; // works
          Provider.of<CalendarData>(context).working = "beer"; // works
          print(Provider.of<CalendarData>(context).working); // works

          return Scaffold(body: SchedulingPage());
        }),
      ),
    );
  }
}

输出:

Performing hot restart...                                               
Restarted application in 1,181ms.
I/flutter (25187): constraints: BoxConstraints(w=411.4, h=659.4)
I/flutter (25187): layout initialized
I/flutter (25187): 411.42857142857144
I/flutter (25187): test: 411.42857142857144
I/flutter (25187): width: 411.42857142857144

答案 1 :(得分:0)

您是否尝试过将MultiProvider()放在MaterialApp()上方?

答案 2 :(得分:0)

我发布此邮件的偶然机会是有人遇到与我相同的问题。事实证明,所选解决方案无法解决问题。所编写的代码应该有效。但是,在这种情况下,很难找到解决方案。事实证明,导入本身是不正确的。提供商数据类有两次导入,如下所示:

import 'package:myProject/providers/CalendarData.dart'; 

import 'package:gcfdlayout2/Providers/CalendarData.dart';

我相信这种歧义使IDE迷惑了,尽管它在构建时没有给我任何错误,但在运行时确实给了我错误,但是“找不到提供程序”让我以为它找不到。树中的提供者,而不是代码本身。

我最终发现的方法是使用其他运行代码的方法。最初,我只是使用Visual Studio Code,但从未出现任何错误提示它是导入问题。我改用Android Studio,它通知我CalendarData类有两个导入。