본문 바로가기

Flutter

[Flutter] RxDart 사용과 PublishSubject, BehaviorSubject

개요

RxDart는 Dart를 리액티브 프로그래밍이 가능하게 하는 라이브러리이다. 이번 포스트에서는 RxDart에서 생산 주체인 Subject와 위젯의 StreamBuilder를 활용하는 방법을 간단하게 소개한다. 추가로 PublishSubject와 BehaviorSubject도 소개한다.

 

Bloc.dart

class Bloc {
  List<MyStock> mStocks = [];
  BehaviorSubject<List<MyStock>> _subjectMyStockList;

  Bloc() {
    _subjectMyStockList = BehaviorSubject<List<MyStock>>.seeded(mStocks);
  }

  get myStockObservable => _subjectMyStockList.stream;

  insertFromMyStock(MyStock item) {
    mStocks.add(item);
    _subjectMyStockList.sink.add(mStocks);
  }


  dispose() {
    _subjectMyStockList.close();
  }
}

var bloc = Bloc();

 

Page.dart

Widget _buildMyStocksLayout() {
    return StreamBuilder<List<MyStock>>(
        stream: bloc.myStockObservable, //stream
        builder: (context, snapshot) { 
          if (snapshot.hasData && snapshot.data.length > 0) {
            return ListView(
              physics: NeverScrollableScrollPhysics(),
              shrinkWrap: true,
              children: _buildMyStockTile(snapshot.data),
            );
          } else {
            return ListView.builder(
                physics: NeverScrollableScrollPhysics(),
                shrinkWrap: true,
                itemCount: 2,
                itemBuilder: (context, index) => Container(
                      margin: EdgeInsets.all(5),
                      child: Shimmer.fromColors(
                        baseColor: Colors.grey[200],
                        highlightColor: Colors.grey[100],
                        child: ListTile(
                          tileColor: Colors.grey[200],
                        ),
                      ),
                    ));
          }
        });
  }

 

In Bloc.dart

1. 먼저 관찰 대상이 되는 기본 자료형인 List<MyStock> mStocks를 생성한다.

2. 이벤트를 발행하는 주체인 BehaviorSubject를 생성하고 mStocks를 wrapping한다.

 

 

In Page.dart

3. 가장 상위 위젯을 StreamBuilder로 wrapping한다. (StreamBuilder는 Subscribe를 가능하게 하는 위젯으로 볼 수 있다.)

4. stream의 인자로 bloc의 BehaviorSubject의 stream을 할당하여 관찰을 수행할 수 있게 초기화한다.

 

 

이후  bloc의 insertMyStock 메서드가 호출되면 새로운 아이템이 추가되고 _subjectMyStockList.sink.add(mStocks);가 호출되어 위의 위젯에서 새로운 데이터에 대한 snapshot을 획득할 수 있다. 

 

추가로, bloc이 dispose 될 때 subject를 close한다.

 

참고. Subject의 종류

Subject는 크게 PublishSubject, BehaviorSubject로 나뉜다.

 

PublishSubject

PublishSubject는 정확히 구독(subscribe)를 시작한 시점부터의 데이터만 전송받을 수 있다.

PublishSubject의 스트림에서 빨간색, 녹색, 파란색이 순서대로 발행되는 상황이다. 두번째 화살표에선 빨간색이 발행되기 전에 구독을 시작하여 모든색을 수신한다. 하지만, 마지막 화살표는 녹색이 발행된 직후 구독하기 시작하여 파란색만 수신할 수 있다.

 

BehaviorSubject

BehaviorSubject의 경우 구독한 시점에서 가장 최신의 값을 받을 수 있다. 즉, 구독하자마자 구독하기 바로 직전 값을 받을 수 있다. 이후는 PublishSubject 처럼 순서대로 수신한다.

BehaviorSubject의 초기 값으로 분홍색이 존재하고 빨간색, 녹색, 파란색이 순서대로 발행되는 상황이다. 먼저 두번째 화살표에서 빨간색이 발행되기 전에 구독을 시작한다. 이 때, 가장 직전의 값인 초기값을 수신할 수 있다. 이후 빨간색, 녹색, 파란색을 순서대로 수신할 수 있다. 마지막 화살표의 경우 녹색이 발행된 후에 구독을 시작한다. 그럼에도 녹색은 가장 최신의 값이었기 때문에 녹색을 수신할 수 있다. 이후 파란색이 발행되어 수신한다. 추가로, 다이어그램에서 보이는 것 처럼 BehaviorSubject는 초기값인 seed가 필요하다.