이벤트 버스는 애플리케이션의 여러 컴포넌트 사이에서 데이터 이벤트를 전달하는 역할을 하는 시스템이다.
그림과 같이 3개의 구성요소로 이루어져 있다.
그래서 이 이벤트 버스를 어떤 상황에 활용할 수 있을까...???
이벤트 버스는 컴포넌트 간의 상호작용에 모두 활용할 수 있지만, 전혀 관련이 없는 컴포넌트들 간의 상호작용에 있어서 가장 빛을 발한다고 생각한다!!
나의 경우, 한 화면에서의 이벤트가 다른 화면에 영향을 줄 때 사용한다.
예를 들어, 인스타의 팔로우/팔로우 취소 이벤트가 있다.
유저의 팔로잉 목록 -> 상대방 프로필 이동 후 팔로잉 취소 -> 뒤로 가기
상대방 프로필 화면에서 발생한 팔로잉 취소
라는 이벤트가 이전 화면인 유저의 팔로잉 목록 화면에 영향을 미친다!
그래서 이를 안드로이드에서 어떻게 구현할 수 있냐면.... SharedFlow
를 통해서 구현할 수 있다!!
SharedFlow 는 동일한 이벤트를 여러 구독자에게 동시에 전송할 수 있는 멀티캐스팅을 지원하며, replayCache
를 통해 최근에 발생한 이벤트들을 일정 수만큼 캐싱 처리해, 새로운 구독자가 발생하더라도 해당 이벤트들을 즉시 받아보도록 할 수 있다.
object EventBus {
private val _events = MutableSharedFlow<UserEvent>()
val events = _events.asSharedFlow()
suspend fun postEvent(event: Event) {
_events.emit(event)
}
suspend inline fun <reified T> subscribeEvent(
crossinline onEvent: (T) -> Unit
) {
events.filterIsInstance<T>()
.collect { event ->
coroutineContext.ensureActive()
onEvent(event)
}
}
}
sealed class Event {
data class FollowUserEvent(
val userId: Int,
val isFollowed: Boolean
) : Event()
}
이를 이용해 발행자의 경우 postEvent
, 수신자의 경우 subscribeEvent
를 통해 이벤트를 수신할 수 있다.
class FollowListViewModel : ViewModel() {
init {
viewModelScope.launch {
UserEventBus.subscribeEvent<UserEvent> { event ->
when (event) {
is Event.FollowUserEvent -> {
// 유저 목록을 보여주는 상태값 변경
}
}
}
}
}
}
class OpponentProfileViewModel : ViewModel() {
fun modifyFollwStatus(targetUserId: Int, isFollowed: Boolean) {
UserEventBus.postEvent(
Event.FollowUserEvent(
targetUserId,
status == FollowStatus.FOLLOW
)
)
}
}
앞서 예시를 들었던 인스타 팔로잉 취소 이벤트를 구현한 예시이다.
object로 EventBus를 구현했기 때문에, 원하는 곳에서 EventBus의 메소드를 호출할 수 있다.