How to listen firebase updates in real time in Flutter

1,936

Solution 1

How you are using this stream matters. await for starts listening to the user, then you do return currentUser; in it and break the await for. Therefore, it cannot keep listening to the stream in the future.

Instead of the return currentUser; inside await for, you can do something like setState((){this.renderedUser = currentUser;}) so that the user that comes from the server becomes the rendered one. If you do that, also add if (!mounted) return; inside the await for so that you stop listening to it when you realize you are in a different screen.

A better alternative may be to use the StreamBuilder widget.

Solution 2

If you run your current code, and make a change to the database, the print statement should be run again. That's because the snapshots is already listening for changes to the database, and calling your code when those happens.

The problem is that you return a Future<User> and a future can only be resolved (get a value) once. If you want to return live data that'd be a Stream<User> (and typically a StreamBuilder instead of a FutureBuilder to build a UI from it).

Share:
1,936
wierdo
Author by

wierdo

Updated on November 28, 2022

Comments

  • wierdo
    wierdo over 1 year

    I have a stream which read user data from firebase. I trigger it after signin, it works perfectly. I show the data in my appbar. When I update firebase manually, I want to see the new date instantly on my appbar. First, I guessed there is something wrong with my appbar but then I noticed that my stream do not triggered when I update firebase data. Here is my stream code snippet. What am I missing?

    static Future<User> userDataStream(userID) async {
        print("userDataStream");
    
        final databaseReference = Firestore.instance;
        User currentUser = User();
    
        await for (var snapshot in databaseReference
            .collection('users')
            .where('userID', isEqualTo: userID)
            .snapshots()) {
          currentUser.userName = snapshot.documents.first.data['userName'];
          currentUser.email = snapshot.documents.first.data['email'];
          currentUser.userID = snapshot.documents.first.data['userID'];
          currentUser.level = snapshot.documents.first.data['level'];
          currentUser.balance = snapshot.documents.first.data['balance'];
    
          print(currentUser.balance);
    
          return currentUser;
        }
    
        return currentUser;
      }
    
  • Gazihan Alankus
    Gazihan Alankus almost 4 years
    I think print won't execute after a modification to the database because await for gets the first state of the database and quits, because of the return statement in it.
  • wierdo
    wierdo almost 4 years
    yes, print won't execute after data update. But when I don't return currentUser in await, it returns nothing. What is the most appropriate way to return the currentUser?
  • Gazihan Alankus
    Gazihan Alankus almost 4 years
    you just should not return anything. you should "get it done" in this function using setState. If you want to return values again and again, your function would need to return a Stream (you can do this easily with async* and yield) but it defeats the purpose, you already have a Stream by calling .snapshots(). So, you should either restructre your app to use StreamBuilder or call setState in this function.
  • wierdo
    wierdo almost 4 years
    thanks, I converted it to a void function. And handle UI side with a StreamBuilder. Now it updates data instantly.