Search code examples
fluttereventsstreamstreamcontroller

Flutter: how do I add event to existing Stream?


I'm using the Stream that is returned by FirebaseAuth.instance.idTokenChanges() in a StreamProvider, to update the whole underlying Widget-tree everytime a user signs up/in/out.

When I update the displayName for example, is there a way I can manually add an event to that Stream, so that the StreamBuidler rebuilds the widget tree with the NEW user data (new displayName), so that the changes display in the UI?

Can I maybe access the controller associated with the stream, so I can call .sink.add() on it? Or is there any other way?


Solution

  • I have figured out a solution: using the StreamGroup class to combine two (or more) streams into one.

    Important, this is from the Flutter async package, not dart async:

    import 'dart:async'; //async await and all that...
    import 'package:async/async.dart'; //this contains StreamGroup
    

    ...

      static StreamController<User> _ctrl;
      static Future<void> initCombinedStream() async {
    
        //without the following line, I get this Error on hot restart: "Bad state: Stream has already been listened to."
        //maybe that error could also be caused by other reasons
        dispose();
    
        _ctrl = StreamController<User>();
    
        StreamGroup streamGroup = StreamGroup<User>();
        await streamGroup
          ..add(_ctrl.stream) //I use this stream when I want to update user info from my code
          ..add(FirebaseAuth.instance.idTokenChanges()) //normal firebase stuff...
          ..close();
        _combinedStream = streamGroup.stream;
      }
    
      ///this is also called from the overridden dispose() method of the highest StatefulWidget in my app
      static void dispose() {
        if (_ctrl != null) _ctrl.close();
      }
    
      //called when updating displayName for example, otherwise that wouldn't update in the UI
      static void updateUserStream() {
        await FirebaseAuth.instance.currentUser.reload(); //no need to call this, this User object is already updated
        _ctrl.add(FirebaseAuth.instance.currentUser); 
      }