EventBus: wat is het, werkingsprincipe en Android-gebeurtenisbus

Auteur: IT Sectr Gepubliceerd: 2026-03-18 Leestijd: 10 min

EventBus is een bibliotheek voor Android die het Publisher-Subscriber-patroon implementeert via een gebeurtenisbus, waardoor gegevens kunnen worden uitgewisseld tussen componenten zonder directe afhankelijkheid. Ontwikkeld door GreenRobot, vereenvoudigt de bibliotheek communicatie tussen Activity, Fragment, Service en Background Thread. Volgens GitHub-gegevens (2025) heeft EventBus meer dan 25 duizend sterren en wordt het gebruikt in duizenden Android-applicaties. De belangrijkste operaties zijn subscribe (abonneren op een gebeurtenis), post (verzenden van een gebeurtenis) en sticky event (uitgestelde gebeurtenis voor nieuwe abonnees).

Belangrijkste punten

  • EventBus — bibliotheek voor gebeurtenisbus voor losgekoppelde communicatie in Android.
  • @Subscribe — annotatie die een methode markeert als afhandelaar van een gebeurtenis van een bepaald type.
  • EventBus.getDefault().post() verzendt de gebeurtenis naar alle geabonneerde afhandelaars.
  • Sticky event bewaart de laatste gebeurtenis voor levering aan nieuwe abonnees.
  • ThreadMode bepaalt de thread van uitvoering van de afhandelaar: MAIN, POSTING, BACKGROUND, ASYNC.

Wat is EventBus?

EventBus is een gebeurtenisbusbibliotheek voor Android die het Publisher-Subscriber-patroon (uitgever-abonnee) implementeert. Het maakt het mogelijk om gebeurtenissen tussen applicatiecomponenten (Activity, Fragment, Service, ViewModel) te verzenden zonder expliciete afhankelijkheden tussen hen te creëren. In tegenstelling tot standaard Android-mechanismen (Intent, BroadcastReceiver) werkt EventBus binnen het proces en gebruikt het geen IPC. De bibliotheek is geoptimaliseerd voor prestaties en gebruikt geen reflectie wanneer Subscriber Index correct is geconfigureerd.

GreenRobot EventBus: architectuur

De architectuur van EventBus bestaat uit drie sleutelelementen: Event (POJO-klasse met gegevens), Subscriber (object met methoden gemarkeerd met @Subscribe) en EventBus (centrale dispatcher). De abonnee registreert zich via EventBus.getDefault().register(this), afmelden — via unregister(this). Gebeurtenissen zijn getypeerd: afhandelaars abonneren zich op een specifieke gebeurtenisklasse en worden alleen aangeroepen bij post van een gebeurtenis van deze klasse of zijn subklassen.

kotlin
// POJO-gebeurtenis
data class MessageEvent(
    val message: String,
    val timestamp: Long = System.currentTimeMillis()
)

// Abonnee in Activity
class MainActivity : AppCompatActivity() {

    override fun onStart() {
        super.onStart()
        EventBus.getDefault().register(this)
    }

    override fun onStop() {
        EventBus.getDefault().unregister(this)
        super.onStop()
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onMessageEvent(event: MessageEvent) {
        textView.text = event.message
    }
}

// Verzenden van gebeurtenis vanuit een andere component
EventBus.getDefault().post(MessageEvent("Hello from Service"))

Subscriber Index voor prestaties

Standaard gebruikt EventBus reflectie om @Subscribe-methoden te vinden bij register(). Subscriber Index genereert een index van afhandelaars tijdens de compilatiefase via een annotatieprocessor. Dit elimineert de overhead van reflectie en versnelt de registratie. Om dit in te schakelen, voegt u eventbus-annotation-processor toe aan build.gradle. EventBus gebruikt de index automatisch als deze beschikbaar is in het classpath. Zonder index werkt de bibliotheek nog steeds, maar met een lichte prestatievermindering.

Hoe werkt EventBus in Android?

Bij het aanroepen van EventBus.getDefault().post(event) bepaalt de bibliotheek het type gebeurtenis, vindt alle geregistreerde abonnees met @Subscribe-methoden die dit type accepteren en roept ze aan volgens de opgegeven ThreadMode. Het zoeken naar abonnees wordt uitgevoerd via de kaart Class → CopyOnWriteArrayList, die tijdens registratie is opgebouwd. Als een gebeurtenis geen abonnees heeft, eindigt post zonder fout — dit is safe-fail-gedrag.

Levenscyclus van registratie

De abonnee moet zich registreren in onStart() en afmelden in onStop(). Als hij zich registreert in onCreate() en afmeldt in onDestroy(), kan een Activity die zonder aanroep van onDestroy is vernietigd (vanwege finish()) in de abonneelijst blijven. Abonneelek — een van de belangrijkste problemen van EventBus: een Activity die in de abonneelijst blijft, wordt niet door de GC verzameld totdat deze zich afmeldt. Koppel altijd register/unregister in de juiste lifecycle-methoden.

Prioriteit van afhandelaars

De @Subscribe-annotatie ondersteunt de parameter priority (geheel getal, standaard 0). Afhandelaars met een hogere prioriteit worden eerder aangeroepen. cancelEventDelivery() maakt het mogelijk om de levering van de gebeurtenis aan andere abonnees te onderbreken. Dit is handig voor prioritaire afhandelaars (loggen, authenticatie) die de verwerking van de gebeurtenis door lagere abonnees kunnen annuleren. De functie is alleen beschikbaar in de thread die de gebeurtenis verzendt.

kotlin
// Complex voorbeeld met prioriteit
data class NavigationEvent(val screen: String, val data: Bundle)

class NavigationInterceptor {
    @Subscribe(priority = 10, threadMode = ThreadMode.POSTING)
    fun onNavigationEvent(event: NavigationEvent) {
        if (event.screen == "restricted" && !isAuthorized) {
            EventBus.getDefault().cancelEventDelivery(event)
        }
    }
}

class AnalyticsLogger {
    @Subscribe(priority = 5)
    fun logNavigation(event: NavigationEvent) {
        analytics.logScreen(event.screen)
    }
}

// Verzenden van gebeurtenis
EventBus.getDefault().post(NavigationEvent("profile", bundle))

EventBus vs LocalBroadcastManager vs LiveData

Android biedt verschillende mechanismen voor intraprocescommunicatie: EventBus, LocalBroadcastManager (verouderd) en LiveData/Flow. Elk heeft zijn voor- en nadelen. De keuze hangt af van de architecturale benadering en prestatievereisten. De moderne aanbevelingen van Google neigen naar LiveData en Flow vanwege de integratie met Lifecycle en het ontbreken van lekken.

KenmerkEventBusLocalBroadcastManagerLiveData / Flow
TyperingVia gebeurtenisklasseVia Intent filter (String)Via generiek type
Lifecycle-awareNee (handmatig afmelden)Nee (handmatig afmelden)Ja (automatisch)
StickyJa (postSticky)NeeJa (LiveData — altijd sticky)
ThreadModeMAIN, POSTING, BACKGROUND, ASYNCAlleen mainVia observe/observeOn
PrestatiesHoog (Subscriber Index)Gemiddeld (IPC-verpakking)Hoog (observatie)

Wanneer EventBus de voorkeur heeft

EventBus is nuttig in projecten met legacy code en waar LiveData/Flow niet beschikbaar zijn (Java-only projecten). Sticky events van EventBus bieden flexibiliteit die ontbreekt in LocalBroadcastManager. EventBus is ook eenvoudiger voor het verzenden van gebeurtenissen van Service naar Activity zonder ViewModel — vooral wanneer u moet melden over de voortgang van een achtergrondtaak. De bibliotheek heeft een minimale omvang (ongeveer 50 KB) en voegt geen afhankelijkheden toe.

Wanneer LiveData/Flow de voorkeur hebben

LiveData en Flow maken deel uit van Android Jetpack en zijn geïntegreerd met Lifecycle. Ze melden zich automatisch af bij vernietiging van de component, waardoor geheugenlekken worden geëlimineerd. Flow ondersteunt coroutines en complexe transformatieoperators. Google beveelt LiveData aan voor de UI-laag en Flow voor repositories. EventBus blijft voor cross-module gebeurtenissen waar navigatie en bedrijfslogica niet passen in MVVM.

Subscribe en Post: basisoperaties

Subscribe — registratie van een gebeurtenisafhandelaar via de @Subscribe-annotatie. De methode moet public, void zijn en precies één parameter accepteren — het gebeurtenistype. Post — verzenden van de gebeurtenis naar alle geabonneerde afhandelaars via EventBus.getDefault().post(event). De post-methode retourneert geen resultaat en meldt niet hoeveel afhandelaars zijn aangeroepen. Voor gebeurtenissen met een antwoord gebruikt u een aparte Event-klasse met een veld voor het resultaat.

Aangepaste gebeurtenissen maken

Een gebeurtenis is elke Java/Kotlin-klasse. Het wordt aanbevolen om data class te gebruiken voor onveranderlijke gebeurtenissen en een gewone klasse voor gebeurtenissen met mutable-velden. De naamgeving van gebeurtenissen moet de actie weerspiegelen: UserLoggedInEvent, DataLoadedEvent, NetworkErrorEvent. Vermijd één gemeenschappelijke Event-klasse met een String type-veld — dit ontneemt de voordelen van typering. Hiërarchie van gebeurtenissen (ouder Event) maakt abonneren op een groep verwante gebeurtenissen mogelijk.

kotlin
// Hiërarchie van gebeurtenissen
open class UserEvent
data class UserLoggedIn(val userId: String) : UserEvent()
data class UserLoggedOut(val reason: String) : UserEvent()

// Abonneren op basisklasse
class SessionManager {
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onUserEvent(event: UserEvent) {
        when (event) {
            is UserLoggedIn -> startSession(event.userId)
            is UserLoggedOut -> endSession(event.reason)
        }
    }
}

// Verzenden
EventBus.getDefault().post(UserLoggedIn("user_123"))

Registratie en afmelding

De aanroep EventBus.getDefault().register(this) scant de klasse van de abonnee via reflectie of Subscriber Index en slaat de gevonden @Subscribe-methoden op in de gebeurteniskaart. Unregister verwijdert de abonnee uit de kaart. Opnieuw registreren zonder afmelden — fout (MultipleSubscriberException treedt op). Voor Fragment registreert u in onStart() en meldt u af in onStop(). Voor Service — in onCreate() en onDestroy(). Voor ViewModel wordt het niet aanbevolen — gebruik LiveData.

Sticky Events en ThreadMode

Sticky event — een gebeurtenis die na verzending in EventBus wordt bewaard. Nieuwe abonnees die na postSticky() zijn geregistreerd, ontvangen onmiddellijk de laatste sticky-gebeurtenis van het overeenkomstige type. Dit is handig voor het doorgeven van de begintoestand: bij het openen van een scherm ontvangt het de laatste gegevens die vóór zijn registratie zijn verzonden. Het verwijderen van een sticky-gebeurtenis kan via EventBus.getDefault().removeStickyEvent(Class).

ThreadMode: vier uitvoeringsmodi

ThreadMode bepaalt in welke thread de afhandelaar wordt aangeroepen. POSTING (standaard) — de afhandelaar wordt uitgevoerd in dezelfde thread waarin post is aangeroepen. MAIN — de afhandelaar wordt uitgevoerd in de main thread via Handler. BACKGROUND — de afhandelaar wordt uitgevoerd in een background thread; als post in de main thread is aangeroepen, plaatst EventBus de afhandelaar in de wachtrij van de background thread. ASYNC — elke afhandelaar wordt uitgevoerd in een afzonderlijke background thread uit de threadpool. Gebruik MAIN voor UI-updates.

kotlin
// Sticky Event
data class LocationEvent(val lat: Double, val lng: Double)

// Verzenden van sticky-gebeurtenis vanuit LocationService
EventBus.getDefault().postSticky(LocationEvent(55.7558, 37.6173))

// Abonnee ontvangt onmiddellijk de laatste locatie na registratie
class MapFragment : Fragment() {
    override fun onStart() {
        super.onStart()
        EventBus.getDefault().register(this)
        // Ontvangt onmiddellijk LocationEvent als postSticky is aangeroepen
    }

    override fun onStop() {
        EventBus.getDefault().unregister(this)
        super.onStop()
    }

    @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
    fun onLocationEvent(event: LocationEvent) {
        moveMapTo(event.lat, event.lng)
    }
}

// Verwijderen van sticky-gebeurtenis
EventBus.getDefault().removeStickyEvent(LocationEvent::class.java)

ThreadMode.BACKGROUND vs ASYNC

BACKGROUND gebruikt één background-thread voor alle afhandelaars — ze worden sequentieel uitgevoerd. ASYNC maakt een nieuwe thread uit de pool voor elke afhandelaar — ze worden parallel uitgevoerd. BACKGROUND is geschikt voor invoer-/uitvoeroperaties met een gedeelde database. ASYNC — voor onafhankelijke lange operaties (netwerkverzoeken). Beide modi vereisen thread-safe toegang tot gedeelde bronnen. Aantal threads: de ASYNC-pool is onbeperkt.

Veelgemaakte fouten en prestaties van EventBus

Bij het gebruik van EventBus maken ontwikkelaars vaak fouten die leiden tot geheugenlekken, onverwachte aanroepen en prestatievermindering. De meest kritieke: vergeten afmelden in Activity, registratie in onCreate (in plaats van onStart/onStop), abonneren op Object (alle gebeurtenissen), verzenden van gebeurtenissen in een oneindige lus. Profilering via Android Profiler helpt bij het identificeren van problemen.

Geheugenlekken via EventBus

De meest voorkomende fout — registratie van Activity in onCreate() zonder afmelden in onDestroy(). Resultaat: EventBus houdt een referentie naar de Activity vast, de GC kan deze niet vrijgeven. Bij draaien van het scherm wordt een nieuwe Activity gemaakt, de vorige blijft in het geheugen. Oplossing: koppel altijd register/unregister in onStart/onStop. Gebruik hetzelfde schema voor Fragment. Als Activity na finish door EventBus wordt vastgehouden, controleer dan via Memory Profiler.

Prestaties: Subscriber Index

Zonder Subscriber Index gebruikt EventBus reflectie om @Subscribe-methoden te vinden bij elke register(). Op apparaten met Android 6-7 werkt reflectie traag, wat vertragingen tot 50 ms veroorzaakt. Subscriber Index elimineert reflectie volledig: methoden worden tijdens de compilatiefase geïndexeerd via een annotatieprocessor. Voor projecten met 20+ abonnees is de index verplicht. Controleer of kapt of annotationProcessor is aangesloten in build.gradle.

groovy
// build.gradle (app) — aansluiten van Subscriber Index
dependencies {
    implementation 'org.greenrobot:eventbus:3.3.1'
    annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.3.1'
}

// Gebruik kapt voor Kotlin
plugins {
    id 'kotlin-kapt'
}

dependencies {
    implementation 'org.greenrobot:eventbus:3.3.1'
    kapt 'org.greenrobot:eventbus-annotation-processor:3.3.1'
}

// Configuratie van de index (in defaultConfig)
kapt {
    arguments {
        arg('eventBusIndex', 'com.app.EventBusIndex')
    }
}

Alternatieven voor EventBus in modern Android

Moderne projecten op Kotlin en Jetpack Compose geven de voorkeur aan SharedFlow en Channel uit de bibliotheek kotlinx.coroutines. SharedFlow ondersteunt replay (sticky), buffering en backpressure. Channel — eenmalige gebeurtenissen (toast, navigatie). Beide oplossingen zijn geïntegreerd met Lifecycle via repeatOnLifecycle en vereisen geen handmatige afmelding. Voor nieuwe projecten wordt SharedFlow aanbevolen in plaats van EventBus. Voor bestaande projecten is migratie gerechtvaardigd bij refactoring.

Veelgestelde vragen

Wat is het verschil tussen EventBus en LiveData?

EventBus is een gebeurtenisbus voor gegevensuitwisseling tussen willekeurige componenten (Activity, Fragment, Service). LiveData is een lifecycle-aware wrapper voor gegevens die door een UI-component worden geobserveerd. LiveData beheert automatisch abonnementen via Lifecycle. EventBus vereist handmatig register/unregister. LiveData wordt aanbevolen voor de UI-laag, EventBus — voor cross-module communicatie waar LiveData onhandig is.

Wat is een sticky event?

Sticky event — een gebeurtenis die na verzending in EventBus wordt bewaard. Nieuwe abonnees die na postSticky() zijn geregistreerd, ontvangen onmiddellijk de laatste sticky-gebeurtenis. Gebruikt voor de begintoestand: bij het openen van een scherm ontvangt het de laatste gegevens zonder een herhaald verzoek. Verwijderd via removeStickyEvent() of bij verzending van een nieuwe sticky-gebeurtenis van hetzelfde type.

Is EventBus thread-safe?

Ja, EventBus is thread-safe. De aanroep post() is mogelijk vanuit elke thread. De levering van de gebeurtenis aan abonnees wordt binnen de bibliotheek gesynchroniseerd. ThreadMode bepaalt de uitvoeringsthread van de afhandelaar: MAIN (main thread via Handler), POSTING (verzender-thread), BACKGROUND (wachtrij achtergrondtaken), ASYNC (afzonderlijke thread). Gebruik MAIN voor UI-updates, ASYNC voor zware operaties.

Hoe debug je EventBus?

Schakel logging in via EventBus.builder().logNoSubscriberMessages(true).sendNoSubscriberEvent(true).install(). Abonneer u op NoSubscriberEvent voor het volgen van gebeurtenissen zonder afhandelaars. Gebruik SubscriberExceptionEvent voor globale afhandeling van uitzonderingen. Android Profiler helpt bij het vinden van lekken. Schrijf voor complexe scenario's een test: EventBus.getDefault().register(mock) + post(event) + verify(mock).

Kan EventBus worden gebruikt in Kotlin Multiplatform?

Nee, EventBus (GreenRobot) is gebonden aan Android SDK en JVM. Gebruik voor Kotlin Multiplatform Kotlin Multiplatform SharedFlow of KMMBus — bibliotheken die gedeelde code ondersteunen. EventBus werkt aan de Android-kant van een KMM-project, maar is niet beschikbaar in commonMain. Voor cross-platform gebeurtenissen hebben native platformmechanismen of abstractie via expect/actual de voorkeur.

Samenvatting

  • EventBus — Publisher-Subscriber-bibliotheek voor Android, die een gebeurtenisbus implementeert met typering via POJO-klassen.
  • De @Subscribe-annotatie met parameters threadMode, sticky, priority bepaalt het gedrag van de gebeurtenisafhandelaar.
  • post() verzendt de gebeurtenis synchroon naar alle abonnees; postSticky() bewaart de gebeurtenis voor nieuwe abonnees.
  • ThreadMode beheert de uitvoeringsthread: POSTING (verzender-thread), MAIN (UI), BACKGROUND (wachtrij), ASYNC (pool).
  • Subscriber Index van de annotatieprocessor elimineert reflectie en versnelt de registratie.
  • Geheugenlekken worden voorkomen door register/unregister te koppelen in onStart/onStop van Activity of Fragment.
  • Voor nieuwe projecten hebben SharedFlow/Channel uit kotlinx.coroutines de voorkeur — ze zijn lifecycle-aware en thread-safe.

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook