본문 바로가기

코틀린/코루틴

Flow 1차 스터디(Hot vs Cold, shared vs state)

기본 용어정리

  • Cold flow vs Hot flow (이해해야하는 기본개념 🚨)

cold, hot은 flow 뿐만 아니라 RX 등등 Stream개념이 사용되는 곳에서 통용된다.

위키피디아에서 찾은 Stream 의 정의는 이러하다

컴퓨터 처리 환경에서 스트림(stream)은 시간이 지남에 따라 사용할 수 있게 되는 일련의 데이터 요소를 가리키는 수많은 방식에서 쓰인다.

이런식으로 개발에서 일반적으로 쓰이는 데이터의 형태를 정의한것이다.

이러한 스트림을 특징에 맞춰서 크게 두 분류로 나눈것이 Cold Hot 인것이다.

 

분류기준

  • 데이터의 생성위치
  • 리시버의 수 (multiCast, UniCast)
  • 데이터 방출 시점(Laziness)

 

cold

  • 스트림 내부에서 데이터 생성

Cold stream 인 flow는 Flow builder block 내에서만 emit 가 가능하다 (내부에서만 데이터 생성가능)

  • uniCast

소비자 하나당 생산자 하나가 배치된다고 생각하면 된다. -> 항상 같은 결과같을 받는다.

  • Lazy

결과 값을 받는 행위를 할때 생산이 된다 ex) collect 할때 데이터가 생성된다.

 

-> 일반적인 flow

 

HOT

  • 스트림 외부에서 데이터 생성

Hot stream 인 channel 은 send 를 통해 외부의 값을 넣어줄 수 있다.

  • multiCast

소비자가 몇이든 넣어준값이 Queue처럼 보관되다가 방출된다. -> 명확히 따지면 다르지만 대충 행동양식이 큐랑 비슷하다.

  • Not Lazy -> 이미 데이터는 방출중

생산자가 넣어둔것을 Queue처럼 보관했다가 방출하므로 어떤시점에 꺼내냐에 따라서 받는 값이 달라질 수 있다.

Ex) 생산자 1,2,3,4,5 를 넣음 소비자1 mendel Activity에서 3번 receive한 후(결과값 1,2,3) 소비자 2 ringring Activity에서 2번 receive한다면 (결과값2,3)서로 다른 결과 값을 받게된다.

 

-> stateFlow,sharedFlow,channel

Channel,Flow 차이의 이해를 돕는 자료

 


LiveData를 대체하자(stateFlow, sharedFlow) -> hot flow

stateFlow

코틀린 공식문서 내용요약:

 

1. 라이브데이터 처럼 데이터 홀더 역할을 하는것에 대한 설명

2. 데이터의 변경은 압축(conflated) 되어 전달된다고함 그래서 콜렉터에서 생략되는 경우도 있지만 결론적으로 가장최근에 방출된 값을 전달받는다함

3. 다양한 flow의 중간연산자를 사용한다면 이점이있다. + combine라는 연산자를 통해서 여러값들을 연계하는데 편리하다.

val sumFlow: Flow<Int> = aModel.counter.combine(bModel.counter) { a, b -> a + b }

4. combind 함수는 flow를 5개까지 인자로 받을 수 있는 함수가 오버로딩 되어있고 그 이후는 vararg로 처리되어있다.

5. meditator livedata와 비슷하다

6. stateFlow는 Any.equals 를 통하여 새로들어오는 value값을 비교하고 그값이 다르면 구독자에게 새값을 뿌린다.

7. stateflow 를 sharedflow 로 구현했다는 이야기와 구현방법 -> 만약 추가 버퍼링 초기값 생략등의 전략이 필요한경우 shared flow를 커스텀하라

8. ConflatedBroadcastChannel이라는것이 있는데 StateFlow로 대체가능하고 더 좋으니 State flow를 사용하라고 한다.

9. 동시성: 딸려있는 모든 메서드가 thread-safe하다고 한다.

10. 상속해서 무언가를 하지말라 -> 인터페이스에 향후 메서드가 추가될 수 있다고 한다 구현이 필요하다면 MutableStateFlow(value)의 생성자를 이용하자

sharedFlow

코틀린 공식문서 내용요약:

 

1. 당연한 소리이지만 Event를 broadCasting 하는 용도로 적절하다고 한다.

2. coldflow 를 shareIn 함수를 통해 Shared flow 로 변환하여 여러 곳에서 동시에 사용할 수 있도록 만들수있다.

3. 리플레이 캐시에 설정한 만큼 최근 값을 보존한다.

4. 새롭게 구독한다면 리플레이 캐스에있는 값들을 받고 추후 새로 업데이트 되는 값들을 받는다.

5. 이 캐시 크기는 최초 생성할때 replay 라는 파라미터를 통해서 설정해준다.

6. 캐시의 스냅샷은 replayCache 프로퍼티를 통해 확인할 수 있고 MutableSharedFlow.resetReplayCache함수를 통해서 초기화 할 수 있다.

7. 추가적으로 캐시의 값을 꺼낼때 사용할수 있는 버퍼 공간을 제공하는데 이는 방출자를 멈추지 않고 느린구독자가 값을 받을수 있게 해준다. 이는 shared flow 를 초기화할때 버퍼 사이즈를 조정할 수 있는데 extraBufferCapacity 라는 파라미터를 통해 설정한다.

8. 이때 extraBufferCapacity 에 들어가는 enum 값으로

이러한 것들이 있다. 각 동작은 설명에 나와있는 그대로 행동하되

새값을 받을 준비가 안된 구독자가 있을때만 이러한 행동으로 동작하게 된다. 만약 구독자가 없다면 가장 최근 리플레이 값만 저장되며 동작은 트리거되지 않는다.

 

9. 디폴트로 그냥 값을 설정하지않 MutableSharedFlow() 기본생성자로 생성한다면 버퍼고 캐시고 없다. 그래서 모든 구독자가 받을때까지 Suspend 되는것이 기본 설정이다.

10. BroadcastChannel 라는게 있다는데 Shared flow로 대체할수 있고 shared flow 가 더 좋다고 한다.

 

sharedFlow 는 일반적으로 event를 전달하는 용도로 많이 쓰인다.

prnd에서 사용하는 Event 관련 처리 방법 발전사 이글을 참고하면 확고하게 사용방법이 다가올것이다.

 

 

p.s 라이브데이터를 안쓰니까 생명주기를 알아서 다뤄야하는 문제점이 생긴다.(조삼모사아님?)

그래서 라이프사이클 스코프가 계속 나오는데 이글을 참고해보자

-> 여기서 나오는 when어쩌구저쩌구, repeatOnLifecycle 모두 LifeCycleOwner의 함수이다.