Flutter/Dart 문법

[Dart] Stream (Future와 차이점)

Chafle 2023. 3. 24. 20:20
반응형

Future

 

실행 ----------------------await----------------------> 완료(반환값)

 

Future가  1함수-> 1반환값이라면

 

 

Stream은

실행-----반환값1(yield)------반환값2(yield)------반환값3(yield)----반환값4(yield)--------완료

 

1함수 n반환값이다.

 

yield를 통하여 반환값을 완료하기 직전까지 n번 받아낼 수 있다.

 

 

 

 

 


Stream 사용하기 위해서 따로 패키지를 가져와야한다. (Dart에서 기본제공은 아님)

import 'dart:async';

void main() async {
  final controller = StreamController();
  final stream = controller.stream;
  
  }

 

Stream 안에는 listen함수를 사용할 수 있다.

listen은 값이 들어오는 것을 듣고있다

그리고 값이 들어오면 (val) { } 이 함수를 수행하게 돼있다.

 

 

import 'dart:async';


void main() async {
  final controller = StreamController();
  final stream = controller.stream;
  
  final streamListener1 = stream.listen((val){
    
  });
  
  }

 

 

쉽게쉽게 이해하면

 

controller로 값을 넣어주면

controller는 stream으로 값을 뿌려주고

listen은 stream에 값이 들어오는 지를 계속 듣고있고

listen에 붙은 함수는 값이 들어오면 수행할 함수를 수행한다.

 

 

그럼 이제 값을 controller로 넣어보자

import 'dart:async';

void main() async {
  final controller = StreamController();
  final stream = controller.stream;
  
  final streamListener1 = stream.listen((val){
    print('Listener1: $val');
  });
  
  controller.sink.add(1);
  }

controller.sink.add를 통하여 stream으로 값을 흘려준다고 생각하자

stream으로 흘러가는 값들을 listen이 듣고있고,

listen이 값이 들어오는 것이 캐치 되면 print하는 함수를 수행한 것으로 이해하자

 


 

값을 여러 개 흘려보내 보자

 

import 'dart:async';

void main() async {
  final controller = StreamController();
  final stream = controller.stream;

  final streamListener1 = stream.listen((val) {
    print('Listener1: $val');
  });

  controller.sink.add(1);
  controller.sink.add(2);
  controller.sink.add(3);
  controller.sink.add(4);
  controller.sink.add(5);
  controller.sink.add(6);
}

 

 


여러 listener들이 stream의 값을 받아내는 것을 수행 해보자

 

  final controller = StreamController();
  final stream = controller.stream;

이것은 한번만 리스닝을 할 수 있는 소스이다.

 

여러 listen을 생성하기 위해서는

  final controller = StreamController();
  final stream = controller.stream.asBroadcastStream();

asBroadcastStream()으로 해줘야 여러 listen들을 생성할 수 있다.

 

import 'dart:async';

void main() async {
  final controller = StreamController();
  final stream = controller.stream.asBroadcastStream();

  final streamListener1 = stream.listen((val) {
    print('Listener1: $val');
  });
 final streamListener2 = stream.listen((val) {
    print('Listener2: $val');
   
  });
  controller.sink.add(1);
  controller.sink.add(2);
  controller.sink.add(3);
  controller.sink.add(4);
  controller.sink.add(5);
  controller.sink.add(6);
}

 

listen 2개가 각각 값이 들어오고 값을 캐치해서 print를 해낸 것을 알 수 있다.

 


 

즉석으로 stream에 조건을 붙이는 법

 

listener1은 짝수만 반환, listener2는 홀수만 반환하는 것을 수행해보자

 

import 'dart:async';

void main() async {
  final controller = StreamController();
  final stream = controller.stream.asBroadcastStream();

  final streamListener1 = stream.where((val) => val % 2 == 0).listen((val) {
    print('Listener1: $val');
  });
 final streamListener2 = stream.where((val) => val % 2 == 1).listen((val) {
    print('Listener2: $val');
   
  });
  controller.sink.add(1);
  controller.sink.add(2);
  controller.sink.add(3);
  controller.sink.add(4);
  controller.sink.add(5);
  controller.sink.add(6);
}

Functional프로그래밍 처럼 바로 바로 .where로 조건을 걸어서 stream에 조건을 바꿔줄 수 있다.

 

 

 


함수로 stream을 제공하는 방법을 알아보자

 

큰 흐름은

함수의 리턴값을 Stream으로 하고 그 함수를listen하면 된다.

 

 

일단 Future의 형태로

number를 받아서 i가 0~4까지 loop를 돌며 number * i를 리턴받는 함수를 작성해보면

Future<int> calculate(int number) async { 
  for(int i = 0; i < 5; i++){
    return i * number;
  }
}

 요런식으로 작성할 수 있다.

 

 

 

이것을 Future가 아니고 Stream으로 리턴하고 싶다면

Stream<int> calculate(int number) async* { 
  for(int i = 0; i < 5; i++){
    yield i * number;
  }
}

Future-> Stream

async -> async*

return -> yield

 

 

위에서 짠 함수를 listen해보자

 

import 'dart:async';

void main() async {
  calculate(1).listen((val) {
    print('calculate(1): $val');
  });
}

Stream<int> calculate(int number) async* {
  for (int i = 0; i < 5; i++) {
    yield i * number;
  }
}

calculate(1)함수를 .listen한다.

 

 

 


Future함수를 Stream함수에서 사용할 수도 있다.

 

import 'dart:async';

void main() async {
  calculate(1).listen((val) {
    print('calculate(1): $val');
  });
}

Stream<int> calculate(int number) async* {
  for (int i = 0; i < 5; i++) {
    yield i * number;
    
    await Future.delayed(Duration(seconds: 1));
  }
}

await Future.delayed함수를 사용하면 1초에 한번씩 값을 yield할 수 있다.

 

 


 

Stream에서 await를 하는데 async로 하는 것을 직접 보자

 

import 'dart:async';

void main() async {
  calculate(2).listen((val) {
    print('calculate(2): $val');
  });
    calculate(4).listen((val) {
    print('calculate(4): $val');
  });
}

Stream<int> calculate(int number) async* {
  for (int i = 0; i < 5; i++) {
    yield i * number;
    
    await Future.delayed(Duration(seconds: 1));
  }
}

 

 


 

그렇다면 async지만 함수1을 다 수행하고 함수2를 그 뒤에 수행하기 위해서는 어떻게 할까?

(Future라면 함수 앞을 await로 감쌌다)

 

 

Stream은 await 대신 yield*로 함수를 감싸준다.

import 'dart:async';

void main() async {

  playAllStream().listen((val) {
    print(val);
  } );
}

Stream<int> playAllStream() async*{
  yield* calculate(1);
  yield* calculate(1000);
}

 

결과가 calculate(1)을 1초에 하나씩 출력하고

다 마치고 나서

calculate(1000)을 1초에 하나씩 출력 하는 것을 알 수 있다.

 

반응형

'Flutter > Dart 문법' 카테고리의 다른 글

[Flutter] Record  (0) 2023.08.08
[Flutter] list generate  (0) 2023.06.28
[Dart] Async에 대하여 (Future- delayed / await)  (0) 2023.03.24
[Dart] List<Map<>>을 Class로 전환하기(연습)  (0) 2023.03.23
[Dart] cascading  (0) 2023.03.23