Stream

하상현·2024년 5월 1일
2

- 연속적으로 발생하는 데이터의 흐름을 표현하며, 이벤트가 발생할 때마다 새로운 데이터를 제공한다.
- 비동기 방식으로 시간에 따라 변하는 값을 지속적으로 동기화한다.
- Future가 단발성이라면 Stream은 지속적인 변화에 따라 화면을 갱신한다.
- 실시간 분석, 예측, 알림, 감시, 로깅, 모니터링, 스톱워치 등에 활용

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초 기다렸다가 온 데이터입니다

StreamController

스트림을 생성하고 제어하는 데 사용되는 클래스로, 스트림 이벤트를 추가하거나 에러를 추가하는 등의 작업을 수행할 수 있습니다.
예시코드) 버튼을 클릭할 때마다 새로운 이벤트를 발생시키는 스트림

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();
  }
}

StreamBuilder

스트림에서 데이터를 받아 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),
                  );
                }
              })),
    );
  }
}

0개의 댓글