Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter Provider: Provide 2 streams with one dependent on the other

I'm using the provider package. In the root of the widget tree I have a multiprovider:

Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        StreamProvider<FirebaseUser>.value(
            value: FirebaseConnection.getAuthenticationStream()),
        StreamProvider<User>.value(
            value: FirebaseConnection.getUserStream(uid: ???))
      ],
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        initialRoute: LoginScreen.id,
        onGenerateRoute: RouteGenerator.generateRoute,
      ),
    );
  }

The first StreamProvider provides the logged in user from firebase_auth. The second StreamProvider is supposed to provide additional information to that user (stored in the users collection). The problem is that to get the second stream I need the uid of the FirebaseUser provided with the first stream but I don't know how to access it.

Nesting the StreamProviders didn't work because in the second stream I can only access the (wrong) context of the build method (for Provider.of(context))

like image 371
Isaak Avatar asked Jan 02 '20 20:01

Isaak


1 Answers

The solution is to save the second stream (loggedInUserStream) in the state and change it whenever the first stream (authenticationStream) emits a new value (by listening to it) like in the code below:

class _FloatState extends State<Float> {
  StreamSubscription<FirebaseUser> authenticationStreamSubscription;
  Stream<User> loggedInUserStream;

  StreamSubscription<FirebaseUser> setLoggedInUserStream() {
    authenticationStreamSubscription =
        FirebaseConnection.getAuthenticationStream().listen((firebaseUser) {
      loggedInUserStream =
          FirebaseConnection.getUserStream(uid: firebaseUser?.uid);
    });
  }

  @override
  void initState() {
    super.initState();
    authenticationStreamSubscription = setLoggedInUserStream();
  }

  @override
  void dispose() {
    super.dispose();
    authenticationStreamSubscription.cancel();
  }

  @override
  Widget build(BuildContext context) {
    return StreamProvider<User>.value(
      value: loggedInUserStream,
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        initialRoute: LoginScreen.id,
        onGenerateRoute: RouteGenerator.generateRoute,
      ),
    );
  }
}

I only needed the first stream (authenticationStream) to get the second one (loggedInUserStream) so I didn't provide it to the widgets below.

like image 126
Isaak Avatar answered Oct 21 '22 23:10

Isaak