- 연속적으로 발생하는 데이터의 흐름을 표현하며, 이벤트가 발생할 때마다 새로운 데이터를 제공한다.
- 비동기 방식으로 시간에 따라 변하는 값을 지속적으로 동기화한다.
- Future가 단발성이라면 Stream은 지속적인 변화에 따라 화면을 갱신한다.
- 실시간 분석, 예측, 알림, 감시, 로깅, 모니터링, 스톱워치 등에 활용
이벤트의 시퀀스를 나타내는 클래스로, 데이터를 생성하고 이벤트를 수신하는 데 사용됩니다.
예시코드) 여러방식으로 Stream만들어보기
void main() {
Stream.fromIterable([1,2,3,4,5]) // 일반적인 데이터를 다룰 때
.listen((int x) => print('iterable : ${x}'));
Stream.periodic(Duration(seconds: 1), (x) => x) // 1초에 1번씩 동작
.take(5) // 5개까지만 데이터를 처리함.
.listen((x) => print('take : ${x}'));
Stream.fromFuture(getData()) // 비동기 데이터를 처리할 때
.listen((x) => print('from Future : ${x}'));
}
Future<String> getData() async {
await Future.delayed(Duration(seconds: 5)); // 5초간 대기
print("Fetched Data");
return "5초 기다렸다가 온 데이터입니다";
}
// 출력결과
iterable : 1
iterable : 2
iterable : 3
iterable : 4
iterable : 5
take : 0
take : 1
take : 2
take : 3
take : 4
Fetched Data
from Future : 5초 기다렸다가 온 데이터입니다
스트림을 생성하고 제어하는 데 사용되는 클래스로, 스트림 이벤트를 추가하거나 에러를 추가하는 등의 작업을 수행할 수 있습니다.
예시코드) 버튼을 클릭할 때마다 새로운 이벤트를 발생시키는 스트림
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final StreamController<int> _controller = StreamController<int>();
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('StreamController Example'),
),
body: Center(
child: StreamBuilder<int>(
stream: _controller.stream,
builder: (context, snapshot) {
return ElevatedButton(
onPressed: () {
_controller.add(1); // 버튼 클릭 시 이벤트를 추가
},
child: Text('Click me'),
);
},
),
),
),
);
}
void dispose() {
_controller.close(); // 사용이 끝나면 StreamController를 닫아줍니다.
super.dispose();
}
}
스트림에서 데이터를 받아 UI를 빌드하는 데 사용됩니다. 스트림에서 새로운 데이터가 수신될 때마다 UI가 업데이트됩니다.
예시코드)
class FristPage extends StatelessWidget {
const FristPage({super.key});
// 2초마다 카운트를 세는 Stream<int>데이터타입으로 리턴해준다.
Stream<int> _addStreamValue() {
var res = Stream<int>.periodic(Duration(seconds: 2), (counter) => counter);
return res;
}
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: StreamBuilder(
stream: _addStreamValue(),
// initialData: '초기값', 앱을 처음시작하여 아무 데이터가 없을때 표시해줄 값(!snapshot.hasData 대신사용가능)
builder: (context, snapshot) {
//해당 부분은 data를 아직 받아 오지 못했을 때 실행되는 부분
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
//error가 발생하게 될 경우 반환하게 되는 부분
else if (snapshot.hasError) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Error: ${snapshot.error}', // 에러명을 텍스트에 뿌려줌
style: TextStyle(fontSize: 15),
),
);
}
// 데이터를 정상적으로 받아오게 되면 다음 부분을 실행하게 되는 부분
else {
return Text(
snapshot.data.toString(), // 비동기 처리를 통해 받은 데이터를 텍스트에 뿌려줌
style: TextStyle(fontSize: 20),
);
}
})),
);
}
}