Flutter에서 Stream은 비동기 이벤트나 데이터를 처리하는 데 유용한 도구입니다. Stream은 여러 비동기 이벤트를 순차적으로 처리할 수 있게 하며, 네트워크 요청, 실시간 데이터 업데이트 등의 작업에 적합합니다. 이번 글에서는 Flutter에서 Stream을 사용하는 방법과 이를 구현하는 예제를 자세히 살펴보겠습니다.
1. Stream의 기본 개념
Stream은 여러 비동기 이벤트를 처리하기 위한 데이터 스트림입니다. Stream은 데이터를 연속적으로 방출하며, 리스너는 이러한 데이터를 구독하여 처리할 수 있습니다. Stream은 일회성 이벤트를 처리하는 Single-subscription Stream과 여러 리스너가 구독할 수 있는 Broadcast Stream으로 나눌 수 있습니다.
2. Stream 생성
Stream을 생성하는 기본적인 방법은 Stream 클래스의 생성자를 사용하는 것입니다. 또한, StreamController를 사용하여 커스텀 Stream을 생성할 수도 있습니다.
import 'package:flutter/material.dart';
import 'dart:async';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: StreamExample(),
);
}
}
class StreamExample extends StatefulWidget {
@override
_StreamExampleState createState() => _StreamExampleState();
}
class _StreamExampleState extends State<StreamExample> {
late Stream<int> _stream;
late StreamSubscription<int> _subscription;
String _message = 'Waiting for data...';
@override
void initState() {
super.initState();
_stream = _createStream();
_subscription = _stream.listen((data) {
setState(() {
_message = 'Received: $data';
});
});
}
Stream<int> _createStream() async* {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
@override
void dispose() {
_subscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Stream Example')),
body: Center(
child: Text(_message),
),
);
}
}
위 코드는 Stream을 생성하고 데이터를 방출하는 간단한 예제입니다. _createStream 메서드는 1초 간격으로 숫자를 방출하며, listen 메서드를 사용하여 스트림의 데이터를 구독합니다.
3. StreamController 사용
StreamController를 사용하면 더 정교한 Stream을 생성할 수 있습니다. StreamController는 스트림의 데이터 흐름을 제어할 수 있는 컨트롤러를 제공합니다.
import 'package:flutter/material.dart';
import 'dart:async';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: StreamControllerExample(),
);
}
}
class StreamControllerExample extends StatefulWidget {
@override
_StreamControllerExampleState createState() => _StreamControllerExampleState();
}
class _StreamControllerExampleState extends State<StreamControllerExample> {
late StreamController<int> _controller;
late StreamSubscription<int> _subscription;
String _message = 'Waiting for data...';
@override
void initState() {
super.initState();
_controller = StreamController<int>();
_subscription = _controller.stream.listen((data) {
setState(() {
_message = 'Received: $data';
});
});
_startStreaming();
}
void _startStreaming() async {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1));
_controller.add(i);
}
_controller.close();
}
@override
void dispose() {
_subscription.cancel();
_controller.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('StreamController Example')),
body: Center(
child: Text(_message),
),
);
}
}
위 코드는 StreamController를 사용하여 스트림을 생성하고 데이터를 방출하는 예제입니다. _startStreaming 메서드는 1초 간격으로 숫자를 스트림에 추가하며, 스트림이 끝나면 close 메서드를 호출하여 스트림을 닫습니다.
4. StreamBuilder 사용
StreamBuilder 위젯을 사용하면 Stream의 데이터를 쉽게 UI에 반영할 수 있습니다. StreamBuilder는 스트림의 상태 변화를 감지하여 자동으로 UI를 업데이트합니다.
import 'package:flutter/material.dart';
import 'dart:async';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: StreamBuilderExample(),
);
}
}
class StreamBuilderExample extends StatefulWidget {
@override
_StreamBuilderExampleState createState() => _StreamBuilderExampleState();
}
class _StreamBuilderExampleState extends State<StreamBuilderExample> {
late Stream<int> _stream;
@override
void initState() {
super.initState();
_stream = _createStream();
}
Stream<int> _createStream() async* {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('StreamBuilder Example')),
body: Center(
child: StreamBuilder<int>(
stream: _stream,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else if (snapshot.hasData) {
return Text('Received: ${snapshot.data}');
} else {
return Text('Stream is closed');
}
},
),
),
);
}
}
위 코드는 StreamBuilder를 사용하여 스트림의 데이터를 UI에 반영하는 예제입니다. StreamBuilder는 스트림의 상태를 감지하여 적절한 위젯을 반환합니다.
5. Broadcast Stream 사용
Broadcast Stream은 여러 리스너가 동일한 스트림을 구독할 수 있게 합니다. StreamController.broadcast를 사용하여 Broadcast Stream을 생성할 수 있습니다.
import 'package:flutter/material.dart';
import 'dart:async';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BroadcastStreamExample(),
);
}
}
class BroadcastStreamExample extends StatefulWidget {
@override
_BroadcastStreamExampleState createState() => _BroadcastStreamExampleState();
}
class _BroadcastStreamExampleState extends State<BroadcastStreamExample> {
late StreamController<int> _controller;
String _message1 = 'Listener 1: Waiting for data...';
String _message2 = 'Listener 2: Waiting for data...';
@override
void initState() {
super.initState();
_controller = StreamController<int>.broadcast();
_controller.stream.listen((data) {
setState(() {
_message1 = 'Listener 1: Received $data';
});
});
_controller.stream.listen((data) {
setState(() {
_message2 = 'Listener 2: Received $data';
});
});
_startStreaming();
}
void _startStreaming() async {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1));
_controller.add(i);
}
_controller.close();
}
@override
void dispose() {
_controller.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Broadcast Stream Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(_message1),
SizedBox(height: 20),
Text(_message2),
],
),
),
);
}
}
위 코드는 Broadcast Stream을 사용하여 두 개의 리스너가 동일한 스트림을 구독하고 데이터를 수신하는 예제입니다. StreamController.broadcast를 사용하여 Broadcast Stream을 생성하고, 두 개의 리스너가 스트림을 구독하여 데이터를 수신합니다.
결론
Flutter 애플리케이션에서 Stream을 사용하면 비동기 이벤트나 데이터를 효율적으로 처리할 수 있습니다. Stream, StreamController, StreamBuilder, Broadcast Stream을 사용하여 다양한 비동기 작업을 구현하는 방법을 통해 Stream을 효과적으로 활용할 수 있습니다. 이번 글에서 소개한 방법들을 활용하여 Flutter 애플리케이션에서 Stream을 효율적으로 사용해보세요. Stream을 통해 애플리케이션의 성능을 향상시키고, 사용자 경험을 개선할 수 있습니다.
'Flutter' 카테고리의 다른 글
Flutter의 RxDart 사용법 (1) | 2024.10.13 |
---|---|
Flutter의 애니메이션 컨트롤러(Animation Controller) 사용법 (0) | 2024.10.12 |
Flutter의 멀티스레딩(Multithreading) 사용법 (0) | 2024.10.11 |
Flutter의 오디오 플레이어(Audio Player) 사용법 (1) | 2024.10.11 |
Flutter의 비동기 프로그래밍(Asynchronous Programming) 사용법 (0) | 2024.10.10 |