【问题标题】:Unhandled Exception: Error: Could not find the correct Provider<User> above this MyApp Widget未处理的异常:错误:在此 MyApp 小部件上方找不到正确的 Provider<User>
【发布时间】:2021-02-07 18:18:31
【问题描述】:

我正在构建一个用于注册和登录的示例应用, 第一个页面显示的是使用 firebase 的移动身份验证,成功身份验证后,我从 firebase 获取 uid 并尝试与我的云 firestore 集合('user')的 documenteID 匹配。如果它给我 null 然后我想显示 SignupScreen(),否则显示 HomeScreen()。

所以这是我的简单逻辑,但我不知道发生了这种类型的错误,

我也尝试了一些不同的代码

ChangeNotifierProvider(
      create: (BuildContext context) => User(),
    ),

但它仍然显示错误。

这是我的代码。

ma​​in.dart

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:phone_auth_example/homePage.dart';
import 'package:phone_auth_example/signup_screen.dart';
import 'package:provider/provider.dart';

import './signUpPage.dart';
import './user.dart';

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

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

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    final FirebaseAuth auth = FirebaseAuth.instance;

    var checkUser = false;
    void isNewUser() async {
      final FirebaseUser user = await auth.currentUser();
      final uid = user.uid;
      Provider.of<User>(context, listen: false).isUserNew(uid);
      checkUser = Provider.of<User>(context, listen: false).checkUser;
    }

    isNewUser();

    return MultiProvider(
        providers: [
          ChangeNotifierProvider.value(
            value: User(),
          ),
        ],
        child: MaterialApp(
          debugShowCheckedModeBanner: false,
          home: StreamBuilder(
            // ignore: deprecated_member_use
            stream: FirebaseAuth.instance.onAuthStateChanged,
            builder: (ctx, userSnapshot) {
              if (userSnapshot.hasData) {
                if (checkUser) {
                  return SignupScreen();
                } else {
                  return HomePage();
                }
              } else if (userSnapshot.hasError) {
                return CircularProgressIndicator();
              }
              return LoginPage();
            },
          ),
          routes: {
            SignupScreen.routeName: (ctx) => SignupScreen(),
          },
        ),);
  }
}

user.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';

enum UserType {
  Member,
  HigherAuthority,
  SecurityGuard,
}

enum UserStatus {
  Owner,
  Renter,
}

enum OccupancyStatus {
  CurrentlyResiding,
  EmptyHouse,
}

class User with ChangeNotifier {
  final String id;
  final UserType userType;
  final String mobileNumber;
  final String name;
  final String email;
  final String password;
  final String houseNumberId;
  final UserStatus userStatus;
  final OccupancyStatus occupancyStatus;

  User({
    @required this.id,
    @required this.userType,
    @required this.mobileNumber,
    @required this.name,
    @required this.email,
    @required this.password,
    @required this.houseNumberId,
    @required this.userStatus,
    @required this.occupancyStatus,
  });

  bool checkUser;

  Future<void> isUserNew(String userId) async {
    // Get data from firestore
    DocumentSnapshot user =
        await Firestore.instance.collection('user').document(userId).get();

    //print(variable.data == null);

    // Check whether userId is in collection or not
    checkUser = (user.data == null) ? true : false;
  }
}

首先,它打开了完美运行的 LoginPage(),然后它直接转到 HomePage() 而不是 signupPage(),无论 uid 是否匹配,所以这是一个问题,它会显示类似.. .

错误

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

【问题讨论】:

  • 但是从错误日志中,你已经得到了解决方案....我是唯一看到这个的人吗?
  • 您能解释一下解决方案在哪里以及如何实施吗?

标签: firebase flutter dart google-cloud-firestore provider


【解决方案1】:

您的问题是您尝试调用Provider.of&lt;User&gt;(context, listen: false).checkUser,而上下文中尚未提供提供者(因为您在树的下方使用MultiProvider)。

您应该向上移动 MultiProvider。下面是一个实现示例:

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:phone_auth_example/homePage.dart';
import 'package:phone_auth_example/signup_screen.dart';
import 'package:provider/provider.dart';

import './signUpPage.dart';
import './user.dart';

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

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

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    @override
    Widget build(BuildContext context) {
      return MultiProvider(
        providers: [
          ChangeNotifierProvider<User>(
            create: (context) => User(),
          ),
        ],
        builder: (BuildContext context, Widget child) {
          final FirebaseAuth auth = FirebaseAuth.instance;

          var checkUser = false;
          void isNewUser() async {
            final FirebaseUser user = await auth.currentUser();
            final uid = user.uid;
            Provider.of<User>(context, listen: false).isUserNew(uid);
            checkUser = Provider.of<User>(context, listen: false).checkUser;
          }

          isNewUser();

          return child;
        },
        child: MaterialApp(
          debugShowCheckedModeBanner: false,
          home: StreamBuilder(
            // ignore: deprecated_member_use
            stream: FirebaseAuth.instance.onAuthStateChanged,
            builder: (ctx, userSnapshot) {
              if (userSnapshot.hasData) {
                if (checkUser) {
                  return SignupScreen();
                } else {
                  return HomePage();
                }
              } else if (userSnapshot.hasError) {
                return CircularProgressIndicator();
              }
              return LoginPage();
            },
          ),
          routes: {
            SignupScreen.routeName: (ctx) => SignupScreen(),
          },
        ),
      );
    }
  }
}

另外还有2个误用ChangeNotifier:

1 User 类应该扩展 ChangeNotifier。

替换

class User with ChangeNotifier

class User extends ChangeNotifier

如果您已经创建了 ChangeNotifier 的实例(在您的情况下为用户),则应使用 2 ChangeNotifierProvider.value:here is a great explaination of the use cases。既然你没有,你应该像这样使用 ChangeNotifierProvider:

ChangeNotifierProvider<User>(
      create: (context) => User(),
      child: ...
)

【讨论】:

  • 我尝试了您在答案中提到的任何内容,但仍然显示相同的错误。你能再检查一次吗?
  • 你可以试试这个吗?
  • 现在显示如下... 找不到 providerinstaller 的本地模块描述符类。 I/DynamiteModule(26592):考虑本地模块 providerinstaller:0 和远程模块 providerinstaller:0 W/ProviderInstaller(26592):无法加载 providerinstaller 模块:找不到可接受的模块。本地版本为 0,远程版本为 0。 I/Choreographer(26592):跳过 38 帧!应用程序可能在其主线程上做了太多工作。 W/ResourceType(26592):获取资源号 0x00000000 V/NativeCrypto(26592) 的名称时没有包标识符:正在注册
  • 试试“flutter clean”?
猜你喜欢
  • 2021-07-23
  • 2021-02-04
  • 2021-10-27
  • 2021-01-31
  • 2020-08-21
  • 2020-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多