将两个流合并为一个StreamProvider

时间:2019-10-06 17:24:38

标签: flutter dart stream flutter-provider

我有两个流:

  • Stream<FirebaseUser> FirebaseAuth.instance.onAuthStateChanged
  • Stream<User> userService.streamUser(String uid)

我的userService需要经过身份验证的FirebaseUser的uid作为参数。

由于我可能需要在应用程序的多个部分中访问streamUser()流,因此我希望它成为项目根目录的提供者。

这是我的main.dart的样子:

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  Widget build(BuildContext context) {
    var auth = FirebaseAuth.instance;
    var userService = new UserService();
    return MultiProvider(
      providers: [
        Provider<UserService>.value(
          value: userService,
        ),
      ],
      child: MaterialApp(
        home: StreamBuilder<FirebaseUser>(
            stream: auth.onAuthStateChanged,
            builder: (context, snapshot) {
              if (!snapshot.hasData) return LoginPage();
              return StreamProvider<User>.value(
                value: userService.streamUser(snapshot.data.uid),
                child: HomePage(),
              );
            }),
      ),
    );
  }
}

问题是,当我导航到另一个页面时,MaterialApp下面的所有内容都被更改,并且我失去了StreamProvider的上下文。

是否可以将StreamProvider添加到MultiProvider provider-list? 因为当我尝试时,我还必须为FirebaseUser创建另一个onAuthStateChanged流,而且我不知道如何将它们组合为一个提供程序。

2 个答案:

答案 0 :(得分:0)

所以这似乎很好:

StreamProvider<User>.value(
  value: auth.onAuthStateChanged.transform(
    FlatMapStreamTransformer<FirebaseUser, User>(
      (firebaseUser) => userService.streamUser(firebaseUser.uid),
    ),
  ),
),

如果在某些情况下有人对此表示怀疑,请告诉我。

感谢pskink关于flatMap的提示。

答案 1 :(得分:0)

也许您可以尝试这种方法:

main.dart

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        Provider<FirebaseUser>(
          builder: (_) => FirebaseUser(),
        ),
      ],
      child: AuthWidgetBuilder(builder: (context, userSnapshot) {
        return MaterialApp(
          theme: ThemeData(primarySwatch: Colors.indigo),
          home: AuthWidget(userSnapshot: userSnapshot),
        );
      }),
    );
  }
}

AuthWidgetBuilder.dart

  

用于创建需要用户访问的对象相关对象   所有小部件。该小部件应位于[MaterialApp]上方。看到   [AuthWidget],一个使用生成的快照的后代小部件   由这个建造者。

class AuthWidgetBuilder extends StatelessWidget {
  const AuthWidgetBuilder({Key key, @required this.builder}) : super(key: key);
  final Widget Function(BuildContext, AsyncSnapshot<User>) builder;

  @override
  Widget build(BuildContext context) {

    final authService =
        Provider.of<FirebaseUser>(context, listen: false);
    return StreamBuilder<User>(
      stream: authService.onAuthStateChanged,
      builder: (context, snapshot) {

        final User user = snapshot.data;
        if (user != null) {
          return MultiProvider(
            providers: [
              Provider<User>.value(value: user),
              Provider<UserService>(
                builder: (_) => UserService(uid: user.uid),
              ),
            ],
            child: builder(context, snapshot),
          );
        }
        return builder(context, snapshot);
      },
    );
  }
}

AuthWidget.dart

  

根据用户的不同,构建已登录或未登录的用户界面   快照。该小部件应位于[MaterialApp]下方。一个   要使用此小部件,必须先使用[AuthWidgetBuilder]祖先。

class AuthWidget extends StatelessWidget {
  const AuthWidget({Key key, @required this.userSnapshot}) : super(key: key);
  final AsyncSnapshot<User> userSnapshot;

  @override
  Widget build(BuildContext context) {
    if (userSnapshot.connectionState == ConnectionState.active) {
      return userSnapshot.hasData ? HomePage() : SignInPage();
    }
    return Scaffold(
      body: Center(
        child: CircularProgressIndicator(),
      ),
    );
  }
}

这最初来自Andrea Bizotto的高级提供商指南。 但是我根据您上面的代码对一些代码进行了定制。 希望这行得通,祝你好运!

  

参考:   https://www.youtube.com/watch?v=B0QX2woHxaU&list=PLNnAcB93JKV-IarNvMKJv85nmr5nyZis8&index=5