본문 바로가기
Programando/Android

[Android/Kotlin] SharedFlow를 이용한 EventBus 구현

EventBus는 확장성이 뛰어난 반응성 애플리케이션을 구현하기 위한 분산 비동기 아키텍처 패턴으로 이벤트를 비동기적으로 전달하고 처리합니다.

EventBus는 느슨한 결합(loose coupling)과 관심사의 분리(separation of concerns) 원칙을 유지하면서 컴포넌트 간 통신이 가능하며, 개발 복잡도간소화합니다. 따라서 규모가 크고 고도로 분산화된 시스템에 효과적입니다.

그러나 메모리 수요가 증가할 수 있기 때문에 구독자에게 필터링을 통해 데이터를 관리해야 합니다.

 

EventBus

otto 라이브러리(https://github.com/square/otto)나 greenrobot 라이브러리(https://github.com/greenrobot/EventBus)를 통해 구현하거나 혹은 SharedFlow를 이용해서 구현할 수 있습니다. 저는 SharedFlow를 이용해 구현했습니다.

 

Flow

리액티브 프로그래밍에는 하나의 데이터를 발행하는 발행자가 있고, 해당 발행자는 데이터의 소비자에게 지속적으로 데이터를 전달하는 역할을 합니다. 이것을 데이터 스트림이라고 합니다.

Flow는 코루틴에서 데이터 스트림을 구현하기 위해 사용할 수 있습니다. 코루틴에서 Flow는 단일 값만 반환하는 정지 함수와 달리 여러 값을 순차적으로 내보낼 수 있는 유형입니다. Flow 빌더를 사용해 작성되면 Cold Stream으로 동작합니다.

- Cold Stream

구독자가 오로지 하나 뿐이며, 해당 구독자에게만 값을 내보냅니다. 또한 일부 값을 생성하기 위해 실행될 코드 라인은 호출하는 주체에 따라 달라지지 않고, 모든 구독자에 대해 동일하다는 점을 유의해야 합니다.

Cold Stream은 누군가가 구독할 때만 값의 방출이 시작되기 때문에 Lazy Stream이라고 할 수 있습니다.

 

SharedFlow

SharedFlow는 이벤트를 관찰하는데 적합한 Flow이고, Hot Stream으로 동작합니다. 또한 모든 collector가 방출된 값을 얻도록 브로드캐스트 방식으로 모든 방출된 값을 공유합니다.

- Hot Stream

0개 이상의 구독자를 가질 수 있으며 동시에 모든 구독자에게 값을 내보냅니다. 또한 모든 구독자에 대해 하나의 방출만이 있으며 초기화 하지 않고 연결하고 듣기 시작할 수 있습니다. 그렇기 때문에 연결하는 순간에 따라서 다른 데이터를 받을 수 있습니다.

Hot Stream은 구독자 유무와 상관없이 값의 방출은 항상 시작되기 때문에 Eager Stream이라고 할 수 있습니다.

 

반응형

EventBus의 구현

object EventBus {
    /*
    replay :
    collector 가 연결됐을 때, 전달받을 이전 데이터의 개수를 지정한다.
    0일 경우, collect 이후의 데이터부터 전달받고,
    1일 경우, collect 직전의 데이터부터 전달받으며 시작한다.
    */
    private val events = MutableSharedFlow<Any>(replay = 0)
    val mutableEvents = events.asSharedFlow()

    suspend fun post(event: Any) {
        events.emit(event)
    }

    inline fun <reified T> subscribe(): Flow<T> {
        return mutableEvents.filter { it is T }.map { it as T }
    }
}

 

EvnetBus의 사용

이벤트 전송

CoroutineScope(Dispatchers.Main).launch {
    EventBus.post(eventValue)
}

 

이벤트 수신 및 UI 변경

  • MainViewModel
    val textView = ObservableField("")
    
    init {
        viewModelScope.launch {
            // EventBus에서 전송되는 값을 받음
            EventBus.subscribe<Boolean>().collect { value ->
                Log.i(TAG, "eventValue: $value")
                // DataBinding
                textView.set(value)
            }
        }
    }

 

그 외

자료 참조

https://developer.android.com/kotlin/flow/stateflow-and-sharedflow#sharedflow

https://jhleed.tistory.com/163

https://sungbin.land/코틀린-flow-뿌시기-36fbb53300b9

반응형