728x90
728x90
Stream
비동기 데이터의 연속적인 흐름을 처리하는 객체로, 여러 개의 데이터를 순차적으로 전달할 때 사용됩니다. Future가 한 번만 결과를 반환하는 비동기 작업이라면, Stream은 여러 개의 데이터를 지속적으로 받을 수 있는 비동기 방식입니다.
1. Stream의 주요 특징
- 비동기 데이터 스트리밍: 여러 개의 데이터를 순차적으로 전달하며, 데이터가 들어오는 대로 처리 가능.
- 리얼타임 데이터 처리: WebSocket, 센서 데이터, 네트워크 스트리밍 등 실시간 이벤트 처리에 적합.
- 구독(Subscription) 방식: .listen()을 사용하여 데이터가 들어올 때마다 반응할 수 있음.
2. Stream vs Future 차이점
| 기능 | Future | Stream |
| 반환 값 개수 | 단 한 번 | 여러 개 |
| 비동기 처리 방식 | 한 번 완료되면 끝남 | 지속적으로 데이터가 들어옴 |
| 사용 예시 | API 요청, 파일 읽기 | WebSocket, 실시간 센서 데이터 |
Future<int> getFutureData() async {
await Future.delayed(Duration(seconds: 2));
return 42; // 한 번만 반환됨
}
Stream<int> getStreamData() async* {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1));
yield i; // 여러 번 반환됨
}
}
3. Stream 생성 및 사용법
(1) 단순한 Stream 생성
Stream<int> numberStream() async* {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1)); // 1초 대기 후 데이터 전송
yield i; // 스트림에 값 추가
}
}
void main() {
numberStream().listen((data) {
print("Received: $data");
});
}
// Received: 1
// Received: 2
// Received: 3
// Received: 4
// Received: 5
- async* 함수 안에서 yield를 사용하면 데이터를 순차적으로 전달할 수 있음.
- .listen()을 사용하면 스트림에 새로운 데이터가 들어올 때마다 실행됨.
(2) StreamController를 사용한 Stream 생성
Dart에서는 StreamController를 사용하여 수동으로 Stream을 생성하고 데이터를 추가할 수 있습니다.
import 'dart:async';
void main() {
final StreamController<int> controller = StreamController<int>();
// 스트림 리스너 (데이터가 들어올 때마다 실행)
controller.stream.listen((data) {
print("Received: $data");
});
// 데이터 추가 (스트림에 새로운 값 전달)
controller.add(1);
controller.add(2);
controller.add(3);
controller.close(); // 스트림 종료
}
// Received: 1
// Received: 2
// Received: 3
- StreamController를 사용하면 직접 .add()를 통해 데이터 전달 가능.
- .close()를 호출하지 않으면 스트림이 계속 열려 있음.
4. Stream 데이터 처리 (변환 및 필터링)
Dart의 Stream은 데이터를 변환하거나 필터링할 수 있는 여러 기능을 제공합니다.
(1) map()을 이용한 변환
Stream<int> numberStream() async* {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
void main() {
numberStream().map((number) => "Number: $number").listen((data) {
print(data);
});
}
// Number: 1
// Number: 2
// Number: 3
// Number: 4
// Number: 5
(2) where()를 이용한 필터링
void main() {
Stream<int> stream = Stream.fromIterable([1, 2, 3, 4, 5, 6]);
stream.where((number) => number % 2 == 0).listen((data) {
print("Even Number: $data");
});
}
// Even Number: 2
// Even Number: 4
// Even Number: 6
5. Stream의 두 가지 유형
(1) Single Subscription Stream (단일 구독 스트림)
- 일반적으로 한 번만 구독 가능하며, .listen()을 여러 번 호출하면 오류 발생.
- 기본적으로 StreamController는 Single Subscription Stream을 생성.
Stream<int> numberStream() async* {
for (int i = 1; i <= 3; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
void main() {
Stream<int> stream = numberStream();
stream.listen((data) {
print("Listener 1: $data");
});
// 같은 Stream을 다시 구독하면 오류 발생!
// stream.listen((data) {
// print("Listener 2: $data");
// });
}
(2) Broadcast Stream (다중 구독 스트림)
- 여러 개의 리스너가 동일한 스트림을 구독할 수 있음.
- StreamController.broadcast()를 사용하여 생성.
void main() {
final StreamController<int> controller = StreamController<int>.broadcast();
// 여러 개의 리스너 추가 가능
controller.stream.listen((data) {
print("Listener 1: $data");
});
controller.stream.listen((data) {
print("Listener 2: $data");
});
controller.add(1);
controller.add(2);
controller.add(3);
controller.close();
}
// Listener 1: 1
// Listener 2: 1
// Listener 1: 2
// Listener 2: 2
// Listener 1: 3
// Listener 2: 3
- broadcast를 사용하면 하나의 스트림을 여러 리스너가 동시에 구독할 수 있음.
6. Stream 에러 처리
스트림에서 오류가 발생할 수 있으므로 에러 처리를 위한 두 가지 방법을 제공합니다.
(1) .handleError() 사용
Stream<int> errorStream() async* {
yield 1;
throw Exception("Error 발생!");
}
void main() {
errorStream().handleError((error) {
print("Error handled: $error");
}).listen((data) {
print("Received: $data");
});
}
(2) try-catch & onError 사용
void main() {
Stream<int> stream = Stream<int>.error("데이터 로딩 실패");
stream.listen(
(data) {
print("Received: $data");
},
onError: (error) {
print("Caught error: $error");
},
);
}728x90
728x90
'Flutter > 개념' 카테고리의 다른 글
| Dart 기본기 - Dart 3.0 클래스 (1) | 2025.02.05 |
|---|---|
| Dart 기본기 - Future, await, async (3) | 2025.02.05 |
| Dart 기본기 - final vs const 차이 (2) | 2025.02.03 |
| Dart 기본기 - null 사용법 (2) | 2025.02.03 |
| Dart 기본기 - dynamic vs var 차이 (2) | 2025.02.03 |
댓글