Future는 한번의 호출로 하나의 값만을 return할 수 있으나, Stream은 한번 호출로 return을 여러번 할 수 있다.

 

1. listening하고 있는 stream으로 값 전달예제.

import "dart:async";
  
void main()
{
    final controller = StreamController();
    final stream = controller.stream;
  
    final streamListener1 = stream.listen((val)
    {
        print("Listener 1 : $val");
    });
  
    controller.sink.add(1);
    controller.sink.add(2);
    controller.sink.add(3);
    controller.sink.add(4);
    controller.sink.add(5);
}


Listener 1 : 1
Listener 1 : 2
Listener 1 : 3
Listener 1 : 4
Listener 1 : 5

 

2. 2개 이상의 다중 listener로 listening하고 싶다면, stream을 boradcast stream으로 만들어 줘야한다.

import "dart:async";
  
void main()
{
    final controller = StreamController();
    final stream = controller.stream.asBroadcastStream();
  
    final streamListener1 = stream.listen((val)
    {
        print("Listener 1 : $val");
    });
  
    final streamListener2 = stream.listen((val)
    {
        print("Listener 2 : $val");  
    });
  
    controller.sink.add(1);
    controller.sink.add(2);
    controller.sink.add(3);
    controller.sink.add(4);
    controller.sink.add(5);
}


Listener 1 : 1
Listener 2 : 1
Listener 1 : 2
Listener 2 : 2
Listener 1 : 3
Listener 2 : 3
Listener 1 : 4
Listener 2 : 4
Listener 1 : 5
Listener 2 : 5

 

3. 각각의 listener에 functional base로 조건에 따라 분기처리

import "dart:async";
  
void main()
{
    final controller = StreamController();
    final stream = controller.stream.asBroadcastStream();
  
    final streamListener1 = stream.where((val) => val % 2 == 0).listen((val)
    {
        print("Listener 1 : $val");
    });
  
    final streamListener2 = stream.where((val) => val % 2 == 1).listen((val)
    {
        print("Listener 2 : $val");  
    });
  
    controller.sink.add(1);
    controller.sink.add(2);
    controller.sink.add(3);
    controller.sink.add(4);
    controller.sink.add(5);
}


Listener 2 : 1
Listener 1 : 2
Listener 2 : 3
Listener 1 : 4
Listener 2 : 5

 

4. stream을 return하는 함수로 listening하기.

Future를 이용하는 방식에서 return type을 stream으로 return대신 yield로, async를 async*로 바꾸면 된다.

import "dart:async";
  
void main()
{
    var _sum = 0;
  
    // 1. 방법
    calculate(1).listen((val)
    {
        _sum += val;
        print("calculate(1) : $val");
    }).onDone(()
    {
        print(_sum);
    });

    // 2. 방법
    var _stream = calculate(1);
    await _stream.forEach((value)
    {
        _sum += value;
        print("calculate(1) : $value");
    });
  
    print(_sum);
}

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


calculate(1) : 0
calculate(1) : 1
calculate(1) : 2
calculate(1) : 3
calculate(1) : 4
10

 

5. stream return함수에서 await키워드로 순차적으로 진행되도록 하기

Future class를 이용한 방식과 마찬가지로 그냥 await키워드 사용하면 되고,

다중으로 stream을 listening을 하면 비동기로 동시에 실행되는 것을 확인할 수 있다.

import "dart:async";
  
void main()
{
    calculate(1).listen((val)
    {
        print("calculate(1) : $val");
    });
  
    calculate(2).listen((val)
    {
        print("calculate(2) : $val");
    });
}

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




calculate(1) : 0
                  calculate(2) : 0
waiting(1) -> 0
calculate(1) : 1
                  waiting(2) -> 0
                  calculate(2) : 2
waiting(1) -> 1
calculate(1) : 2
                  waiting(2) -> 1
                  calculate(2) : 4
waiting(1) -> 2
calculate(1) : 3
                  waiting(2) -> 2
                  calculate(2) : 6
waiting(1) -> 3
calculate(1) : 4
                  waiting(2) -> 3
                  calculate(2) : 8
waiting(1) -> 4
                  waiting(2) -> 4





// await 키워드 없다면 순차적으로 진행되지 않는다.
calculate(1) : 0
calculate(2) : 0
calculate(1) : 1
calculate(2) : 2
calculate(1) : 2
calculate(2) : 4
calculate(1) : 3
calculate(2) : 6
calculate(1) : 4
calculate(2) : 8
waiting(1) -> 0
waiting(2) -> 0
waiting(1) -> 1
waiting(2) -> 1
waiting(1) -> 2
waiting(2) -> 2
waiting(1) -> 3
waiting(2) -> 3
waiting(1) -> 4
waiting(2) -> 4

 

6. Future class의 await처럼, stream의 listening도 await하도록 하여

하나의 stream이 모두 처리되면 그 다음 stream이 순차적으로 listening하게 하고 싶다면 yield*를 사용하면 된다.

yield*는 해당 stream의 return이 모두 처리될때까지 대기한다.

import "dart:async";
  
void main()
{
    syncCalculate().listen((val)
    {
        print(val);
    });
}

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

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


0
waiting(1) -> 0
1
waiting(1) -> 1
2
waiting(1) -> 2
3
waiting(1) -> 3
4
waiting(1) -> 4
0
waiting(1000) -> 0
1000
waiting(1000) -> 1
2000
waiting(1000) -> 2
3000
waiting(1000) -> 3
4000
waiting(1000) -> 4


// await 키워드 제거하면 syncCalculate함수안에 로직은 순차적으로 진행되나, calculate안쪽 로직은 순차적으로 진행되지 않는다.
0
1
2
3
4
0
1000
2000
3000
4000
waiting(1) -> 0
waiting(1) -> 1
waiting(1) -> 2
waiting(1) -> 3
waiting(1) -> 4
waiting(1000) -> 0
waiting(1000) -> 1
waiting(1000) -> 2
waiting(1000) -> 3
waiting(1000) -> 4

 

참조 : https://www.youtube.com/watch?v=rk41rBXq3zQ