오늘 배울 것
오늘은 StreamBuilder의 개념과 FutureBuilder와의 차이점. 그리고 StreamBuilder의 기본 구조와 각 속성의 의미에 대해 알아보겠습니다.
마지막으로 타이머 예제를 통한 실시간 데이터 UI 갱신을 직접 실습해보겠습니다.
StreamBuilder란?
StreamBuilder는 지속적으로 변하는 데이터를 실시간으로 UI에 반영할 수 있게 해주는 비동기 위젯입니다.
FutureBuilder가 "한 번 받아오는 비동기 데이터"에 적합하다면 StreamBuilder는 "여러 번 지속적으로 들어오는 데이터" 에 적합합니다. 예를 들어, 실시간 채팅 앱이나 센서 데이터, 데이터 스트림과 같은 실시간 데이터 처리에 사용할 수 있습니다.
FutureBuilder vs StreamBuilder
지난 시간에 배운 FutureBuilder 와 특징을 비교해보면 다음 표와 같습니다.
구분 | FutureBuilder | StreamBuilder |
데이터 횟수 | 한 번만 | 여러 번, 지속적으로 |
사용 용도 | API 요청, 파일 읽기 | 센서 값, 채팅, 실시간 알림, 주가 스트리밍 등 |
동작 방식 | 한 번 실행되고 종료 | 스트림을 계속 구독하고 새 데이터 올 때마다 rebuild |
리턴 타입 | Future<T> | Stream<T> |
StreamBuilder 구조
StreamBuilder<T>(
stream: someStream, // 구독할 Stream
builder: (context, AsyncSnapshot<T> snapshot) {
// snapshot: 현재 상태 + 데이터
...
},
);
1. `StreamBuilder<T>`에서 T는 Stream이 내보내는 데이터 타입을 뜻합니다.
- Stream<int>라면 StreamBuilder<int>
- Stream<String>이면 StreamBuilder<String>
- Stream<List<User>>라면 StreamBuilder<List<User>>
이렇게 타입을 지정해줘야 snapshot.data를 쓸 때 타입 추론이 돼서 오류가 줄어듭니다.
2. `stream: someStream` 은 비동기 데이터를 지속적으로 받아오는 Stream 객체가 들어갑니다. 아래는 예시 Stream 객체입니다.
- Stream.periodic(...) → 일정 주기로 데이터 발행
- FirebaseFirestore.instance.collection(...).snapshots() → Firestore 실시간
- WebSocketChannel.stream → 소켓 통신
- StreamController.stream → 직접 만든 스트림
StreamBuilder는 이 stream을 "구독"해서 새 데이터가 들어올 때마다 UI를 자동으로 갱신합니다.
3. `snapshot` 안에는 현재 Stream 상태와 데이터가 들어 있습니다. 새 데이터가 오면 builder는 다시 호출돼서 UI를 다시 빌드해줍니다.
*잠깐! snapshot은 뭔가요?
snapshot은 Future나 Stream의 현재 상태와 데이터를 담고 있는 객체를 말합니다.
FutureBuilder나 StreamBuilder를 사용할 때 builder 함수는 항상 (context, snapshot) 인자를 받습니다. 이때, snapshot 객체는 아래처럼 다양한 상태 정보가 들어 있습니다.
snapshot 상태 정보 | 설명 |
connectionState | 현재 연결 상태 (none, waiting, active, done) |
hasData | 데이터가 있는지 여부 (true or false) |
data | 실제로 받은 데이터 |
hasError | 에러 발생 여부 |
error | 에러가 있다면 그 에러 내용 |
실습 예제: 1초마다 숫자가 증가하는 타이머
아래 코드를 main.dart 파일에 붙여넣기 하고 앱을 실행해주세요.
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(home: MyHomePage());
}
}
class MyHomePage extends StatelessWidget {
// 1초마다 숫자를 증가시키는 Stream 생성
Stream<int> numberStream() {
return Stream.periodic(Duration(seconds: 1), (count) => count);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('StreamBuilder 예제')),
body: Center(
child: StreamBuilder<int>(
stream: numberStream(), // 여기서 스트림을 구독
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("스트림 연결 중...");
} else if (snapshot.hasError) {
return Text("에러 발생: ${snapshot.error}");
} else if (snapshot.hasData) {
return Text('숫자: ${snapshot.data}', style: TextStyle(fontSize: 30));
} else {
return Text("데이터 없음");
}
},
),
),
);
}
}
numberStream() 함수는 Stream.periodic을 이용하여 1초마다 count를 증가시켜서 스트림으로 보냅니다. StreamBuilder는 이 데이터를 받아서 실시간으로 화면의 숫자를 업데이트합니다.
이처럼 StreamBuilder를 이용하면 별도의 상태관리 없이 간결한 코드로 실시간 UI 갱신을 구현할 수 있습니다.
Recap
- StreamBuilder는 실시간 데이터 UI 처리에 적합한 비동기 위젯입니다.
- FutureBuilder는 한 번의 비동기 작업, StreamBuilder는 지속적인 데이터를 받아올 때 사용합니다.
- StreamBuilder<T>에서 T는 스트림이 내보내는 데이터 타입이고 stream은 구독할 스트림 객체입니다.
- StreamBuilder를 사용하면 별도의 상태관리 없이도 실시간 UI 업데이트가 가능합니다.
'Flutter 독학으로 기본기 익히기' 카테고리의 다른 글
07. 비동기 상태에 따라 UI를 바꾸는 FutureBuilder 알아보기 (0) | 2025.05.08 |
---|---|
06. Flutter 비동기 처리 Future, async/await 알아보기 (1) | 2025.05.07 |
05. Flutter Navigator로 화면 이동하는 방법 (0) | 2025.05.06 |
04. Flutter 에서 자주 사용하는 레이아웃 위젯 (0) | 2025.05.03 |
03. 위젯 트리 구조, DevTools 로 Widget Tree 보는 방법 (0) | 2025.05.02 |