DEV Community

Cover image for Event Bus Pattern in Android Using Kotlin Flows
Mohit Rajput
Mohit Rajput

Posted on

Event Bus Pattern in Android Using Kotlin Flows

The event bus design pattern is very popular and advantageous in programming. The publishers trigger events and subscribers can listen to those events from anywhere. It reduces unnecessary coupling. With the arrival of observers and other frameworks, this design pattern is in less use nowadays. To achieve broadcasting of events in Android, we already had the following options:

  • RxBus
  • Local Broadcast
  • Third parties i.e. green robot etc.

While Kotlin is gaining popularity, language is providing so many cutting-edge frameworks. Flow is one of them. Kotlin released a stable version of StateFlow and SharedFlow with the language's 1.4 release. We can achieve the EventBus design pattern using SharedFlow and leverage the benefits of language and framework.

Implementation

You can achieve event bus using shared flow using following easy steps:

Step 1:

Create a generic event bus class as follows:



object EventBus {
  private val _events = MutableSharedFlow<Any>()
  val events = _events.asSharedFlow()

  suspend fun publish(event: Any) {
    _events.emit(event)
  }

  suspend inline fun <reified T> subscribe(crossinline onEvent: (T) -> Unit) {
    events.filterIsInstance<T>()
      .collectLatest { event ->
        coroutineContext.ensureActive()
        onEvent(event)
      }
  }
}


Enter fullscreen mode Exit fullscreen mode

Here, the publish method posts an event passed as a parameter. Subscribe method collects those events. It does some utility work i.e. filtering correct event, ensuring coroutine context is active or not then providing event on the onEvent() method. Moreover, you can collect public events shared flow variable to apply custom logic if needed.

Event Bus Flow

Step 2:

Create an event class as follows:



data class LoginEvent(
  val userId: String,
  val userName: String
)


Enter fullscreen mode Exit fullscreen mode

Ideally, your event classes would be data classes as in any event, you would require some data. But it could be any kind of class.

Step 3:

Now use those methods to publish and subscribe to events. Creating a separate class would be preferred as per module or feature. One example is as follows:



class LoginEventHandler {
  suspend fun postLoginEvent(loginEvent: LoginEvent) {
    EventBus.publish(loginEvent)
  }

  fun subscribeLoginEvent(lifecycleOwner: LifecycleOwner) {
    lifecycleOwner.lifecycleScope.launch {
      EventBus.subscribe<LoginEvent> { loginEvent ->
        Log.d("LoginEventHandler", "${loginEvent.userName} logged-in successfully")
      }
    }
  }
}


Enter fullscreen mode Exit fullscreen mode

And that's it!!!

Conclusion

Event bus has been a debatable topic among developers. Some say it should not be followed because it could act as a single point of failure. Sometimes, it could be hard to debug what is the source of the event.
However, it is widely accepted and useful for many use cases i.e. updating UI on internet connectivity changes, refreshing UI on login once login popup dismisses i.e. in e-commerce apps, etc. In my opinion, don't be too dependent on it. Use it as minimally as possible. Your opinion and approaches are welcome in the comments.

You can check my articles on Medium also.

Top comments (2)

Collapse
 
arthacker8209 profile image
Deepak Kumawat

Very informative đź’Ż

Collapse
 
mohitrajput987 profile image
Mohit Rajput

Thanks