카테고리 없음

10. Reactive programming, rxdart

코딩 잘 할거얌:) 2022. 4. 22. 00:14
반응형

이번 포스팅은 Reactive Programming이 적용된 RxDart와 그걸 Flutter에 적용해보도록 하겠다.

 

실시간으로(출처 : 엠넷)

Reactive Programming이란, 비동기 데이터 스트림을 이용한 프로그래밍하는 것을 말한다. 혹시 자세한 것을 알고 싶다면 포스팅해놓은 것을 참고하기 바란다.

 

https://pcseob.tistory.com/40

 

2. Reactive Programming

오늘은 Reactive Programming에 대해서 알아보도록 하자. Reactive Programming이란 Reactive programming is programming with asynchronous data streams. 비동기 데이터스트림을 이용한 프로그래밍하는 것을..

pcseob.tistory.com

 


버전 정보

Flutter 2.10.5 • channel stable • https://github.com/flutter/flutter.git
Tools • Dart 2.16.2 • DevTools 2.9.2

rxdart: ^0.27.3

 


rxdart

 

실시간으로 데이터가 변하는 rx, dart에서 rx의 Subject를 3가지를 제공하고 있다. 

 

  • PublishSubject
  • BehaviorSubject
  • ReplaySubject

이렇게 3가지가 있다. 이 3가지 방법으로 데이터를 실시간으로 변하는 것을 관찰(Observe)한다. 각각의 기능에 대해서 설명하겠다. 아래의 글에 참고를 많이 하였고, 내가 부족한 부분을 추가해서 설명하도록 하겠다.

 

https://www.woolha.com/tutorials/rxdart-using-subject-publish-behavior-replay

 

RxDart - Using Subject (Publish, Behavior, Replay)

Differences between PublishSubject, BehaviorSubject, ReplaySubject in RxDart and how to use them

www.woolha.com

 

 

 

PublishSubject

 

PublishSubject는 구독하는 시점으로부터 그 이후에 나타나는 이벤트에만 반응을 한다. 

 

출처 : https://reactivex.io/documentation/ko/subject.html

위와 같은 그림처럼 작동하는데, 이 전에 있던 데이터는 관찰을 할 수 없다. 사람이 Youtube에 채널을 구독을 했다고 한다면, 그 시점 이후에 나오는 동영상만 볼 수 있다는 뜻이다. 아래의 코드를 보면서 조금 더 이해해보자.

import 'package:rxdart/rxdart.dart';

void main() {
  PublishSubject publishSubject = PublishSubject<int>();

  publishSubject.stream.listen((value) {
    print('PublishSubject Observer 1: $value');
  });
  
  publishSubject.add(1);
  publishSubject.add(2);

  publishSubject.stream.listen((value) {
    print('PublishSubject Observer 2: $value');
  });
  
  publishSubject.add(3);
  publishSubject.add(4);

  publishSubject.close();
}

//결과 : 
// PublishSubject Observer 1: 1
// PublishSubject Observer 2: 3
// PublishSubject Observer 1: 2
// PublishSubject Observer 2: 4
// PublishSubject Observer 1: 3
// PublishSubject Observer 1: 4

 

 

결과를 보다 보면 분명 이상한 점이 있을 것이다. 위에서 설명했던걸 생각하면, 결괏값은 

// PublishSubject Observer 1: 1
// PublishSubject Observer 1: 2
// PublishSubject Observer 2: 3
// PublishSubject Observer 1: 3
// PublishSubject Observer 2: 4
// PublishSubject Observer 1: 4
 
처럼 되어야할 것 같은데 말이다. 분명 PublishSubject Observer 2를 뒤에 명시를 했는데도 불구하고 먼저나오게 된다.
우리가 구독을 선언한 부분, publishSubject.stream.listen을 한 부분들이 동시에 코드에서 실행된다고 생각하면 된다. 즉 PublishSubject Observer 1 이 한칸 움직여서 1을 출력시키면, 그 다음 PublishSubject Observer 2가 한 칸 움직여서 3을 출력시킨다고 생각하면 된다. 그리고 close에 도달하면 구독을 종료하게 된다.
 
두 번째 코드보고 BehaviorSubject로 넘어가도록 하겠다.
import 'package:rxdart/rxdart.dart';

void main() {
  PublishSubject publishSubject = PublishSubject<int>();

  // Observer1 will receive all data and done events
  publishSubject.stream.listen((value) {
    print('PublishSubject Observer 1: $value');
  });

  publishSubject.add(1);
  publishSubject.add(2);

  // Observer2 will receive all data and done events
  publishSubject.stream.listen((value) {
    print('PublishSubject Observer 2: $value');
  });

  publishSubject.add(3);

  publishSubject.stream.listen((value) {
    print('PublishSubject Observer 3: $value');
  });

  publishSubject.add(4);
  
  publishSubject.close();
}

// PublishSubject Observer 1: 1
// PublishSubject Observer 2: 3
// PublishSubject Observer 3: 4
// PublishSubject Observer 1: 2
// PublishSubject Observer 2: 4
// PublishSubject Observer 1: 3
// PublishSubject Observer 1: 4
 

 

BehaviorSubject

 

BehaviorSubject는 구독하는 시점 이 전의 값을 가져와서 시작한다.

 

출처 : https://reactivex.io/documentation/ko/subject.html

 

BehaviorSubject는 직전에 있던 데이터부터 가져와서 관찰한다. 위와 같은 예시를 들자면, Youtube에 채널을 구독을 했다고 한다면, 그 직전에 나온 동영상부터 볼 수 있다는 뜻이다. 아래의 코드를 보면서 조금 더 이해해보자.

 

import 'package:rxdart/rxdart.dart';

void main() {
  BehaviorSubject behaviorSubject = BehaviorSubject<int>();

  behaviorSubject.stream.listen((value) {
    print('BehaviorSubject Observer 1: $value');
  });

  behaviorSubject.add(1);
  behaviorSubject.add(2);


  behaviorSubject.stream.listen((value) {
    print('BehaviorSubject Observer 2: $value');
  });

  behaviorSubject.add(3);
  behaviorSubject.add(4);

  behaviorSubject.close();
}

// BehaviorSubject Observer 1: 1
// BehaviorSubject Observer 2: 2
// BehaviorSubject Observer 2: 3
// BehaviorSubject Observer 1: 2
// BehaviorSubject Observer 2: 4
// BehaviorSubject Observer 1: 3
// BehaviorSubject Observer 1: 4

 

아까 위에서 봤던 것처럼 우선 구독을 다 하고 그 이후로 한 칸씩 이동한다고 생각하면 되는데, 다만 구독하는 시점 바로 뒷부분도 출력이 되는 것을 알 수 있다. 그래서 BehaviorSubject OBserver 1 : 1이 출력된 후, BehaviorSubject OBserver 1 : 2 rk dkslfk BehaviorSubject OBserver 2 : 2가 먼저 출력되는 것을 볼 수 있다.

 

import 'package:rxdart/rxdart.dart';

void main() {
  BehaviorSubject behaviorSubject = BehaviorSubject<int>.seeded(100);

  behaviorSubject.stream.listen((value) {
    print('BehaviorSubject Observer 1: $value');
  });

  behaviorSubject.add(1);
  behaviorSubject.add(2);


  behaviorSubject.stream.listen((value) {
    print('BehaviorSubject Observer 2: $value');
  });

  behaviorSubject.add(3);

  behaviorSubject.stream.listen((value) {
    print('BehaviorSubject Observer 3: $value');
  });

  behaviorSubject.add(4);
  behaviorSubject.add(5);

  behaviorSubject.close();
}

// BehaviorSubject Observer 1: 100
// BehaviorSubject Observer 1: 1
// BehaviorSubject Observer 2: 2
// BehaviorSubject Observer 2: 3
// BehaviorSubject Observer 3: 3
// BehaviorSubject Observer 3: 4
// BehaviorSubject Observer 1: 2
// BehaviorSubject Observer 2: 4
// BehaviorSubject Observer 3: 5
// BehaviorSubject Observer 1: 3
// BehaviorSubject Observer 2: 5
// BehaviorSubject Observer 1: 4
// BehaviorSubject Observer 1: 5

BehaviorSubject는 seeded라는 것으로 데이터 초기값을 설정해줄 수 있다. 그래서 내가 개인적으로 Flutter에서 Rx를 구현할 때 많이 쓴다.

 

 

ReplaySubject

 

ReplaySubject는 말 그대로 구독하는 순간 데이터를 모두 보게 된다.

 

출처 : https://reactivex.io/documentation/ko/subject.html

코드 순서는 다를 수 있지만 모든 시점을 살필 수 있어서 사실 listen 하는 위치에 크게 영향받지 않는다고 생각하면 된다. 우리가 아는 Youtube의 구독처럼 구독하면 모든 동영상을 볼 수 있다고 생각하면 된다.

 

import 'package:rxdart/rxdart.dart';

void main() {
  ReplaySubject replaySubject = ReplaySubject<int>();


  replaySubject.stream.listen((value) {
    print('ReplaySubject Observer 1: $value');
  });

  replaySubject.add(1);
  replaySubject.add(2);
  replaySubject.stream.listen((value) {
    print('ReplaySubject Observer 2: $value');
  });
  replaySubject.add(3);

  replaySubject.close();
}

// ReplaySubject Observer 1: 1
// ReplaySubject Observer 2: 1
// ReplaySubject Observer 2: 2
// ReplaySubject Observer 2: 3
// ReplaySubject Observer 1: 2
// ReplaySubject Observer 1: 3

 

Replay는 replaysubject.stream.listen 하는 순간 모든 add 되는 데이터를 보게 된다. 다만 모두 볼 수 없는 상황도 존재하는데 그건 최대 데이터를 저장하는 걸 제한할 때 발생한다.

 

import 'package:rxdart/rxdart.dart';

void main() {
  ReplaySubject replaySubject = ReplaySubject<int>(maxSize: 1);

  replaySubject.stream.listen((value) {
    print('ReplaySubject Observer 1: $value');
  });

  replaySubject.add(1);

  replaySubject.add(2);

  replaySubject.add(3);
  replaySubject.stream.listen((value) {
    print('ReplaySubject Observer 2: $value');
  });

  replaySubject.close();
}

// ReplaySubject Observer 1: 1
// ReplaySubject Observer 2: 3
// ReplaySubject Observer 1: 2
// ReplaySubject Observer 1: 3

 

 

다음 포스팅은 이 rxdart를 가지고 stream으로 연결해서 위젯을 직접 커스텀해보도록 하겠다. 

 


오류, 지적사항 그리고 궁금한 것은 댓글 부탁드립니다.

728x90