Listening for Data from Firebase using Streams

[Ko]

 - firestore database messages collection 저장된 text  sender 값을 flutter app에서 불러와서 사용하자.

 - getDocument method 이용해서 firebase collection으로부터 얻어지는 messages future query snapshot 타입의 데이터임. Future<QuerySnapshot> , QuerySnapshot firebase 데이터 타입이며 이를 future 형태로 client 전송함. —> messages.document 이용해서 DocumentSnapshot List 접근할 있으며, 이를 for loop 돌릴 있음.

- for-in문에서 messages.document 1개의 item message 1개의 DocumentSnapshot이며, 여기서 실제 데이터를 사용하기 위해서는 message.data(text,sender map 데이터 타입) 이용.

void getMessages() async {

  final messages = await _firestore.collection('messages').getDocuments();

  for (var message in messages.documents) {

    print(message.data);

  }

}

 

 - 실제로 app에서는 위와 같은 방법으로 메세지를 가지고 오면, 내가 작성하는 메세지가 상대방 app 즉시 나타나게 하려면, getDocument method 1초에도 여러번씩 계속 실행되도록 해야하는데 이는 매우 비효율적이며 resource 낭비가 심하게 . 따라서 작성되는 메세지를 즉시 보여주기 위해서는 stream 이용해야 .

 - 새로운 메세지 데이터가 작성될 때마가 메세지 데이터가 우리의 앱으로 push 되도록 해야 .

 - Stream<QuerySnapshot> 리턴하는 snapshots() method 사용하자. Snapshots method 실제로 제공하는 것은 여러개 future들의 list라고 보면 . For-in 문을 이용해서 stream 형태의 데이터를 차례로 순회할 있으며, for-in 문의 앞에 await 사용하면 steam 형태로 제공되는 마지막 future(최신 변화 내용이 적용된 future)만을 사용할 있다. 마지막 future 이용해서 다시 for문을 돌리면, 전체 대화 목록을 얻을 있음.

 - snapshots method 사용하면 messages collection에서 발생하는 모든 변화를 listening하게 되며, 변화된 최신의 snapshot 반영하기 위해서는 await for-in 문을 사용하면 stream 형태로 제공되는 완성된 snapshot data snapshot 변수에 저장할 있음. 

 

void messagesStream() async {

  await for (var snapshot in _firestore.collection('messages').snapshots()) {

    for (var message in snapshot.documents) {

      print(message.data);

    }

  }

}

 

 - 요약 : 비정기적으로 입력되는 데이터를 변화 발생시에만 push 받기 위해서는 해당 collection stream 형태의 데이터를 반환하는 method 등록하며, method 의해 여러개 future list 들이 stream 방식으로 반환되는데, 최신의 future 얻기 위해서는 stream 제너레이터의 결과물(future list) for-in 문을 적용하고, 마지막 future 얻기 위해서 for-in 문의 앞에 await 적용함.

 

 - final code(chat_screen.dart)

...

  final _firestore = Firestore.instance;

  final _auth = FirebaseAuth.instance;

  FirebaseUser loggedInUser;

  String messageText;

 

  @override

  void initState() {

    // TODO: implement initState

    super.initState();

    getCurrentUser();

  }

 

  void getCurrentUser() async {

    try {

      final user = await _auth.currentUser();

      if (user != null) {

        loggedInUser = user;

        print(loggedInUser.email);

      }

    } catch (e) {

      print(e);

    }

  }

 

//  void getMessages() async {

//    final messages = await _firestore.collection('messages').getDocuments();

//    for (var message in messages.documents) {

//      print(message.data);

//    }

//  }

 

  void messagesStream() async {

    await for (var snapshot in _firestore.collection('messages').snapshots()) {

      for (var message in snapshot.documents) {

        print(message.data);

      }

    }

  }

 

Turning Streams into Widgets Using the StreamBuilder

 

 - flutter에서 제공하는 StreamBuilder 이용하면 stream 형태로 제공되는 data snapshot 중복된 data 반복적으로 화면에 보여주는 비효율성을 제거하면서 widget으로 변환할 있음.

 - StreamBuilder 새로운 stream data 들어올때마다 setState method 실행시킴으로써 변경사항을 반영함.

 - StreamBuilder builder 사용되는 snapshot 이전에 다룬 firebase snapshot 아니라, flutter async snapshot. (실제로 flutter async snapshot firebase snapshot 포함하는 개념임.)

 - flutter async snapshot .data 이용해서 firebase snapshot 접근할 있음. 이렇게 접근한 데이터에 .documents 이용해서 firebase documents 접근.

 

StreamBuilder(

              stream: _firestore.collection('messages').snapshots(),

              builder: (context, snapshot) {

                if (!snapshot.hasData) {

                  return Center(

                    child: CircularProgressIndicator(

                      backgroundColor: Colors.lightBlueAccent,

                    ),

                  );

                }

                  final messages = snapshot.data.documents;

                  List<Text> messageWidgets = [];

                  for (var message in messages) {

                    final messageText = message.data['text'];

                    final messageSender = message.data['sender'];

 

                    final messageWidget =

                        Text('$messageText from $messageSender');

                    messageWidgets.add(messageWidget);

                  }

                  return Column(

                    children: messageWidgets,

                  );

 

              },

            ),

 

[En]

 - Import and use the text and sender values ​​stored in the messages collection in the firestore database in the flutter app.
 - The messages obtained from the firebase collection using the getDocument method are data of the future query snapshot type. Future  That is, QuerySnapshot is a firebase data type and sends it to the client in the future. —> You can access the List of DocumentSnapshot using messages.document, and run a for loop.
- In the for-in statement, the message, which is one item of messages.document, is one DocumentSnapshot. To use the actual data, use message.data (the map data type of text and sender).

void getMessages() async {

  final messages = await _firestore.collection('messages').getDocuments();

  for (var message in messages.documents) {

    print(message.data);

  }

}

 

 - In fact, if you bring a message in the same way as in the app above, in order for the message you write to appear immediately in the other party app, you must keep the getDocument method running several times a second, which is very inefficient and wastes resources. Therefore, stream must be used to immediately display the created message.
 - Whenever new message data is created, we need to ensure that the new message data is pushed to our app.
 - Use the snapshots () method that returns a Stream . What the Snapshots method actually provides is a list of multiple futures. By using the for-in statement, it is possible to iterate through data in the form of stream, and if await is used in front of the for-in statement, only the last future provided in the form of steam (the future with the latest changes) can be used. If you run the for statement again using this last future, you can get the full list of conversations.
 - When using the snapshots method, all changes occurring in the messages collection are listened to. To reflect the latest snapshot, the await for-in statement can be used to store the completed snapshot data provided in the form of a stream in the snapshot variable. .

 

void messagesStream() async {

  await for (var snapshot in _firestore.collection('messages').snapshots()) {

    for (var message in snapshot.documents) {

      print(message.data);

    }

  }

}

 

 - Summary: In order to receive data that is entered irregularly only when a change occurs, register a method that returns data in the form of stream in the collection, and by this method, multiple future lists are returned in a stream manner. To do this, apply the for-in statement to the result of the stream generator (future list), and apply await before the for-in statement to get the last future.

 

 - final code(chat_screen.dart)

...

  final _firestore = Firestore.instance;

  final _auth = FirebaseAuth.instance;

  FirebaseUser loggedInUser;

  String messageText;

 

  @override

  void initState() {

    // TODO: implement initState

    super.initState();

    getCurrentUser();

  }

 

  void getCurrentUser() async {

    try {

      final user = await _auth.currentUser();

      if (user != null) {

        loggedInUser = user;

        print(loggedInUser.email);

      }

    } catch (e) {

      print(e);

    }

  }

 

//  void getMessages() async {

//    final messages = await _firestore.collection('messages').getDocuments();

//    for (var message in messages.documents) {

//      print(message.data);

//    }

//  }

 

  void messagesStream() async {

    await for (var snapshot in _firestore.collection('messages').snapshots()) {

      for (var message in snapshot.documents) {

        print(message.data);

      }

    }

  }

 

Turning Streams into Widgets Using the StreamBuilder

 

 - Using the StreamBuilder provided by flutter, snapshots of data provided in the form of streams can be converted into widgets while removing the inefficiency of repeatedly displaying duplicate data on the screen.
 - StreamBuilder reflects changes by executing setState method whenever new stream data comes in.
 - The snapshot used in the builder of StreamBuilder is not a snapshot of the firebase discussed previous, but an async snapshot of flutter. (Actually, flutter's async snapshot is a concept that includes a snapshot of firebase.)
 - You can access the snapshot of firebase using .data in flutter's async snapshot. Access the documents in the firebase using .documents on the accessed data.

 

StreamBuilder(

              stream: _firestore.collection('messages').snapshots(),

              builder: (context, snapshot) {

                if (!snapshot.hasData) {

                  return Center(

                    child: CircularProgressIndicator(

                      backgroundColor: Colors.lightBlueAccent,

                    ),

                  );

                }

                  final messages = snapshot.data.documents;

                  List<Text> messageWidgets = [];

                  for (var message in messages) {

                    final messageText = message.data['text'];

                    final messageSender = message.data['sender'];

 

                    final messageWidget =

                        Text('$messageText from $messageSender');

                    messageWidgets.add(messageWidget);

                  }

                  return Column(

                    children: messageWidgets,

                  );

 

              },

            ),

'플러터(Flutter) > 플러터 일반(Flutter General)' 카테고리의 다른 글

How to programmatically exit the app in flutter  (0) 2020.06.06
stream data listening  (0) 2020.04.23
setup Firebase Project  (0) 2020.03.19
[Dart] Mixins  (0) 2020.03.19
Hero Animation  (0) 2020.03.19

+ Recent posts