Challenge 3
- Flutter course
- Advanced
- Lesson 68/69
- 3 min
Build a realtime chat screen with Firestore.
Challenge 3 - Firestore chat
In this challenge you will listen to messages from a Firestore collection with snapshots() and display them with a StreamBuilder. Each time a message is added, the stream emits new data.
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('messages')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Text('loading');
return Text('${snapshot.data!.docs.length} messages');
},
)Practice First data with StreamController
In main, create a StreamController holding List<String> (streamCtrl). Add a three-element list to it. Await the first data with streamCtrl.stream.first and print its length. Then call streamCtrl.close().
Starter code
import 'dart:async';
void main() async {
// List<String> tutan bir StreamController oluştur (streamCtrl)
// içine üç elemanlı bir liste ekle
// stream'in ilk verisini bekle ve length'ini yazdır
}Sample solution
import 'dart:async';
void main() async {
final streamCtrl = StreamController<List<String>>();
streamCtrl.add(['a', 'b', 'c']);
final data = await streamCtrl.stream.first;
print(data.length);
streamCtrl.close();
}Expected output
3
Practice Create a StreamBuilder widget
In main, create a StreamController holding List<String> (streamCtrl). Create a StreamBuilder<List<String>> widget: set stream to streamCtrl.stream; the builder returns Text(snapshot.data!.length.toString()) if snapshot.hasData, else Text('yok'). Print the widget's runtimeType and call streamCtrl.close().
Starter code
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
// List<String> tutan bir StreamController oluştur (streamCtrl)
// StreamBuilder oluştur: stream olarak streamCtrl.stream ver
// builder snapshot hasData ise data length string, değilse 'yok'
// widget'ın runtimeType'ını yazdır
}Sample solution
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
final streamCtrl = StreamController<List<String>>();
final widget = StreamBuilder<List<String>>(
stream: streamCtrl.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.length.toString());
}
return const Text('yok');
},
);
print(widget.runtimeType);
streamCtrl.close();
}Expected output
StreamBuilder<List<String>>
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What type of object does snapshots() return?
- Stream<QuerySnapshot> Correct answer
- Future<QuerySnapshot>
- QuerySnapshot
- List<DocumentSnapshot>
Explanation: snapshots() returns a Stream<QuerySnapshot>; a new snapshot is emitted on every data change.
2 Give stream to StreamBuilder
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('messages')
.____(),
builder: (context, snapshot) { ... },
)
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('messages')
.snapshots(),
builder: (context, snapshot) { ... },
)
Explanation: Calling snapshots() on a collection returns a real-time Stream<QuerySnapshot>; get returns a one-shot Future.
3 Firestore chat matches
| Term | Meaning |
|---|---|
Firestore |
Database |
snapshots |
Real-time stream |
StreamBuilder |
Binds stream to widget |
QuerySnapshot |
Query result |