Event Bus and Observer Pattern in Kotlin: Implementation and Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Event Bus and Observer Pattern in Kotlin: Architecture of Event-Driven Applications



Modern development in Kotlin, especially in the context of Android and server applications, requires flexible mechanisms for interaction between components. The Observer pattern and its practical implementation — Event Bus — provide an elegant solution for loosely coupled architecture, where one object (publisher) notifies multiple subscribers about an event without knowing their specific implementation. In this article, we will explore how to build your own Event Bus in Kotlin using coroutines and type safety.



Observer Pattern: Theoretical Foundation



The Observer pattern defines a one-to-many dependency between objects. When the state of a subject (publisher) changes, all dependent objects (observers) are automatically notified and updated. In Kotlin, this pattern can be implemented through interfaces, lambdas, or more advanced constructs.



Key elements of the pattern:

  • Subject — an object that manages a list of observers and sends notifications.
  • Observer — an object that receives notifications from the subject.
  • ConcreteSubject — a concrete implementation of the subject with its own state.
  • ConcreteObserver — a concrete implementation of the observer that reacts to changes.


Example of a simple implementation in Kotlin:



interface Observer {    fun update(event: String)}

class ConcreteSubject { private val observers = mutableListOf<Observer>()

fun attach(observer: Observer) { observers.add(observer) }

fun detach(observer: Observer) { observers.remove(observer) }

fun notifyObservers(event: String) { observers.forEach { it.update(event) } }}

class ConcreteObserver(private val name: String) : Observer { override fun update(event: String) { println("$name received event: $event") }}

fun main() { val subject = ConcreteSubject() val observer1 = ConcreteObserver("Observer 1") val observer2 = ConcreteObserver("Observer 2")

subject.attach(observer1) subject.attach(observer2) subject.notifyObservers("Data updated")}


Event Bus: Practical Event Bus



Event Bus is a centralized mechanism that extends the Observer pattern. Instead of each subject managing its own observers, a single bus is created through which all events pass. This simplifies communication between components, especially in complex applications.



Advantages of Event Bus:

  • Loose coupling: publishers and subscribers do not know about each other.
  • Ease of adding new subscribers without modifying existing code.
  • Ability to filter events by type or tag.
  • Support for asynchronous processing via coroutines.


Implementing Event Bus in Kotlin with Coroutines



A modern Event Bus implementation must account for multithreading and avoid memory leaks. Using Coroutines and Channel allows creating a thread-safe and efficient bus.



Basic Event Bus implementation:



import kotlinx.coroutines.*import kotlinx.coroutines.channels.Channelimport kotlinx.coroutines.flow.*

sealed class Event { data class UserLoggedIn(val userId: String) : Event() data class DataUpdated(val data: String) : Event() object NetworkError : Event()}

class EventBus { private val _events = MutableSharedFlow<Event>(extraBufferCapacity = 64) val events: SharedFlow<Event> = _events.asSharedFlow()

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

fun subscribe(scope: CoroutineScope, action: (Even

Recommendations