MultiProvider 和抽象类

时间:2020-12-22 08:13:41

标签: flutter dart provider bloc

美好的一天!

如何使用 MaterialApp 的提供程序?我有一个 MultiProvider 和抽象类。需要将 auth 传递给 LandingPage

这是我想获得的:

 Widget build(BuildContext context) {
    return Provider<AuthBase>(
      create: (context) => Auth(),
      child: MaterialApp(
        title: "Bloc Test",
        theme: ThemeData(primarySwatch: Colors.indigo),
        home: LandingPage(),
      ),
    );
  }

这是我的工作代码:

 class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MultiProvider(
          providers: [
            ChangeNotifierProvider<ToDoProvider>(
              create: (ctx) => ToDoProvider(),
            ),
          ],
          child: MaterialApp(
            debugShowCheckedModeBanner: false,
            title: 'Ultimative ToDo',
            theme: ThemeData(
              scaffoldBackgroundColor: myListMainColor,
            textTheme:
                  GoogleFonts.sourceSansProTextTheme(Theme.of(context).textTheme),
              visualDensity: VisualDensity.adaptivePlatformDensity,
             
            ),
            initialRoute: '/',
            routes: {
              '/': (context) => LandingPage(auth: Auth()),
              OpenedToDo.routeName: (context) => OpenedToDo(),
             },
          ),

我有一个抽象类 AuthBase,但我不能将它与 ChangeNotifier 混合使用。所以这就是我不能将新的代码字符串放入 MultiProvider 的原因。

abstract class AuthBase {
  User get currentUser;
  Future<User> signInAnonymously();
  Stream<User> authStateChanges();
  Future<void> singOut(BuildContext context);
  Future<User> singInWithGoogle();
  Future<User> createUserWithEmailAndPassword(String email, String password);
  Future<User> signInWithEmailAndPassword(String email, String password);
}

class Auth implements AuthBase {
  final _firebaseAuth = FirebaseAuth.instance;

  @override
  Stream<User> authStateChanges() => _firebaseAuth.authStateChanges();

  @override
  User get currentUser => _firebaseAuth.currentUser;

  @override
  Future<User> signInAnonymously() async {
  
  }

  @override
  Future<User> signInWithEmailAndPassword(String email, String password) async {
   
  }

  @override
  Future<User> createUserWithEmailAndPassword(
   
  }

  @override
  Future<User> singInWithGoogle() async {
  
  }

  @override
  Future<void> singOut(BuildContext context) async {
   
  }
}

错误是:

<块引用>

错误:在此之上找不到正确的提供者 StreamBuilder 小部件

这可能是因为您使用的 BuildContext 包括您选择的提供商。有几种常见的情况:

  • 您尝试读取的提供程序位于不同的路径中。

    提供者是“有范围的”。所以如果你在路由中插入 provider, 那么其他路由将无法访问该提供程序。

  • 您使用了 BuildContext,它是您尝试读取的提供程序的祖先。

    确保 StreamBuilder 在您的 多提供者/提供者。这通常发生在你 创建一个提供者并尝试立即读取它。

    例如,代替:

      return Provider<Example>(
        create: (_) => Example(),
        // Will throw a ProviderNotFoundError, because `context` is associated
        // to the widget that is the parent of `Provider<Example>`
        child: Text(context.watch<Example>()),
      ),   }   ```
    
    consider using `builder` like so:
    
    ```   Widget build(BuildContext context) {
      return Provider<Example>(
        create: (_) => Example(),
        // we use `builder` to obtain a new `BuildContext` that has access to the provider
        builder: (context) {
          // No longer throws
          return Text(context.watch<Example>()),
        }
      ),   }   ```
    

登陆页面:

 @override
  Widget build(BuildContext context) {
    return StreamBuilder(
      stream: auth.authStateChanges(),
      builder: (context, snapshot) {
        //* если подключился к данным
        if (snapshot.connectionState == ConnectionState.active) {
          //* получаем данные о пользователе
          final User user = snapshot.data;

          print('~ uid is ${user?.uid}');

          if (user == null) {
            //Navigator.of(context).pushNamed(SignInPage.routeName, arguments: auth);

            return SignInPage.create(context);
          } else {
            // Navigator.of(context).pushNamed(HomeScreen.routeName);
            return HomeScreen();
          }
        }
        return Scaffold(
          body: Center(
            child: CircularProgressIndicator(),
          ),
        );
      },
    );
  }

SignInPage 有这部分代码:

 static Widget create(BuildContext context) {
    final auth = Provider.of<AuthBase>(context, listen: false);
    return Provider<SignInBloc>(
      create: (_) => SignInBloc(auth: auth),
      //* обязательно должен быть dispose
      dispose: (_, bloc) => bloc.dispose(),
      //* consumer помогает прокинуть данные в конструктор
      child: Consumer<SignInBloc>(
        child: SignInPage(),
        builder: (_, bloc, __) => SignInPage(bloc: bloc),
      ),
    );
  }

2 个答案:

答案 0 :(得分:0)

在转到问题的抽象主题之前,我建议在主文件夹上启动 MultiProvider。 像这样

import 'package:provider/provider.dart' as provider;

void main() {
  runApp(provider.MultiProvider(
    providers: [
      provider.ChangeNotifierProvider.value(value: Prov1()),
      provider.ChangeNotifierProvider.value(value: Prov2()),
      provider.ChangeNotifierProvider.value(value: Prov3()),
      provider.ChangeNotifierProvider.value(value: Prov4()),
    ],
    child: MyApp(),
  ));
}

从此时起,您可能可以在应用的任何位置进行访问。 也许在实现抽象类的类上使用您想要的提供程序,而不是直接在其上更改数据。希望我能帮上忙并把事情弄清楚。

答案 1 :(得分:0)

好的,我找到了解决方法。这很容易。 所以在 multiProvider 代码部分的 main.dart 中,我应该只添加一个字符串:

 class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MultiProvider(
          providers: [
        ChangeNotifierProvider<ToDoProvider>(
          create: (ctx) => ToDoProvider(),
        ),
        THIS CODE ==> Provider<AuthBase>.value(value: Auth()),
      ],
      child: MaterialApp(
...

LandingPage.dart:

class LandingPage extends StatelessWidget {
  static const routeName = '/landingPage';

  @override
  Widget build(BuildContext context) {
    final auth = Provider.of<AuthBase>(context, listen: false);
    return StreamBuilder(
      stream: auth.authStateChanges(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.active) {
          final User user = snapshot.data;
          print('~ uid is ${user?.uid}');
            if (user == null) {
            return SignInPage.create(context);
          } else {
            // Navigator.of(context).pushNamed(HomeScreen.routeName);
            return HomeScreen();
          }
        }
        return Scaffold(
          body: Center(
            child: CircularProgressIndicator(),
          ),
        );
      },
    );
  }
}

在 SignInPage.dart 中:

static Widget create(BuildContext context) {
    final auth = Provider.of<AuthBase>(context, listen: false);
    return Provider<SignInBloc>(
      create: (_) => SignInBloc(auth: auth),
      dispose: (_, bloc) => bloc.dispose(),
      child: Consumer<SignInBloc>(
        child: SignInPage(),
        builder: (_, bloc, __) => SignInPage(bloc: bloc),
      ),
    );
  }

所以因为 AuthBase 是一个抽象类,所以我不能将它与 ChangeNotifier 混合,但我不需要,因为这个类不是可变的。这就是我使用 Provider.value(value: value) 的原因。

相关问题