EventBus ist eine Bibliothek für Android, die das Publisher-Subscriber-Muster über einen Event-Bus implementiert und den Datenaustausch zwischen Komponenten ohne direkte Abhängigkeiten ermöglicht. Entwickelt von GreenRobot, vereinfacht die Bibliothek die Kommunikation zwischen Activity, Fragment, Service und Background Thread. Laut GitHub-Daten (2025) hat EventBus über 25.000 Sterne und wird in Tausenden von Android-Anwendungen verwendet. Die Hauptoperationen sind subscribe (Abonnieren eines Ereignisses), post (Senden eines Ereignisses) und sticky event (verzögertes Ereignis für neue Abonnenten).
Wichtige Punkte
EventBus ist eine Event-Bus-Bibliothek für Android, die das Publisher-Subscriber-Muster implementiert. Sie ermöglicht das Übergeben von Ereignissen zwischen Anwendungskomponenten (Activity, Fragment, Service, ViewModel), ohne explizite Abhängigkeiten zwischen ihnen zu schaffen. Im Gegensatz zu den standardmäßigen Android-Mechanismen (Intent, BroadcastReceiver) arbeitet EventBus prozessintern und verwendet kein IPC. Die Bibliothek ist für Leistung optimiert und verwendet keine Reflektion, wenn der Subscriber Index richtig konfiguriert ist.
Die EventBus-Architektur besteht aus drei Schlüsselelementen: Event (POJO-Klasse mit Daten), Subscriber (Objekt mit @Subscribe-annotierten Methoden) und EventBus (zentraler Verteiler). Der Abonnent registriert sich über EventBus.getDefault().register(this) und meldet sich über unregister(this) ab. Ereignisse sind typisiert: Handler abonnieren eine bestimmte Ereignisklasse und werden nur aufgerufen, wenn ein Ereignis dieser Klasse oder ihrer Unterklassen gepostet wird.
// POJO-Ereignis
data class MessageEvent(
val message: String,
val timestamp: Long = System.currentTimeMillis()
)
// Abonnent 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
}
}
// Senden eines Ereignisses von einer anderen Komponente
EventBus.getDefault().post(MessageEvent("Hello from Service"))
Standardmäßig verwendet EventBus Reflektion, um @Subscribe-Methoden während register() zu finden. Subscriber Index erzeugt zur Kompilierzeit über einen Annotationsprozessor einen Handler-Index. Dies eliminiert den Reflektions-Overhead und beschleunigt die Registrierung. Zum Aktivieren fügen Sie eventbus-annotation-processor zu build.gradle hinzu. EventBus verwendet den Index automatisch, wenn er im Classpath verfügbar ist. Ohne den Index funktioniert die Bibliothek weiterhin, jedoch mit einer leichten Leistungseinbuße.
Wenn EventBus.getDefault().post(event) aufgerufen wird, bestimmt die Bibliothek den Ereignistyp, findet alle registrierten Abonnenten mit @Subscribe-Methoden, die diesen Typ akzeptieren, und ruft sie gemäß dem angegebenen ThreadMode auf. Die Abonnentensuche erfolgt über eine Class → CopyOnWriteArrayList-
Ein Abonnent sollte sich in onStart() registrieren und in onStop() abmelden. Wenn Sie sich in onCreate() registrieren und in onDestroy() abmelden, kann eine ohne Aufruf von onDestroy (aufgrund von finish()) zerstörte Activity in der Abonnentenliste verbleiben. Abonnentenleck ist eines der Hauptprobleme von EventBus: Eine in der Abonnentenliste verbleibende Activity wird vom GC erst freigegeben, wenn sie sich abmeldet. Paaren Sie register/unregister immer in den richtigen Lifecycle-Methoden.
Die @Subscribe-Annotation unterstützt einen priority-Parameter (ganze Zahl, Standard 0). Handler mit höherer Priorität werden zuerst aufgerufen. cancelEventDelivery() ermöglicht die Unterbrechung der Ereigniszustellung an verbleibende Abonnenten. Dies ist nützlich für prioritäre Handler (Protokollierung, Authentifizierung), die die Ereignisverarbeitung durch nachgelagerte Abonnenten abbrechen können. Diese Funktion ist nur im Ereignis-Posting-Thread verfügbar.
// Komplexes Beispiel mit Priorität
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)
}
}
// Senden eines Ereignisses
EventBus.getDefault().post(NavigationEvent("profile", bundle))
Android bietet mehrere Mechanismen für die prozessinterne Kommunikation: EventBus, LocalBroadcastManager (veraltet) und LiveData/Flow. Jeder hat seine Vor- und Nachteile. Die Wahl hängt vom architektonischen Ansatz und den Leistungsanforderungen ab. Googles moderne Empfehlungen tendieren aufgrund der Lifecycle-Integration und der Abwesenheit von Lecks zu LiveData und Flow.
| Merkmal | EventBus | LocalBroadcastManager | LiveData / Flow |
|---|---|---|---|
| Typisierung | Über Ereignisklasse | Über Intent-Filter (String) | Über generischen Typ |
| Lifecycle-aware | Nein (manuelle Abmeldung) | Nein (manuelle Abmeldung) | Ja (automatisch) |
| Sticky | Ja (postSticky) | Nein | Ja (LiveData ist immer sticky) |
| ThreadMode | MAIN, POSTING, BACKGROUND, ASYNC | Nur main | Über observe/observeOn |
| Leistung | Hoch (Subscriber Index) | Mittel (IPC-Wrapper) | Hoch (Überwachung) |
EventBus ist nützlich in Projekten mit umfangreichem Legacy-Code und wo LiveData/Flow nicht verfügbar sind (nur Java-Projekte). Die Sticky Events von EventBus bieten Flexibilität, die in LocalBroadcastManager fehlt. EventBus ist auch einfacher zum Senden von Ereignissen von Service zu Activity ohne ViewModel — besonders wenn Sie den Fortschritt einer Hintergrundaufgabe benachrichtigen müssen. Die Bibliothek hat eine minimale Größe (ca. 50 KB) und fügt keine Abhängigkeiten hinzu.
LiveData und Flow sind Teil von Android Jetpack und in den Lifecycle integriert. Sie melden sich automatisch ab, wenn eine Komponente zerstört wird, und eliminieren so Speicherlecks. Flow unterstützt Coroutinen und komplexe Transformationsoperatoren. Google empfiehlt LiveData für die UI-Ebene und Flow für Repositories. EventBus bleibt nützlich für modulübergreifende Ereignisse, bei denen Navigation und Geschäftslogik nicht in MVVM passen.
Subscribe ist die Registrierung eines Ereignishandlers über die @Subscribe-Annotation. Die Methode muss public, void sein und genau einen Parameter — den Ereignistyp — akzeptieren. Post ist das Senden eines Ereignisses an alle abonnierten Handler über EventBus.getDefault().post(event). Die post-Methode gibt kein Ergebnis zurück und zeigt nicht an, wie viele Handler aufgerufen wurden. Für Ereignisse mit Antwort verwenden Sie eine separate Event-Klasse mit einem Ergebnisfeld.
Ein Ereignis ist jede Java/Kotlin-Klasse. Es wird empfohlen, data class für unveränderliche Ereignisse und eine normale Klasse für Ereignisse mit veränderlichen Feldern zu verwenden. Die Ereignisbenennung sollte die Aktion widerspiegeln: UserLoggedInEvent, DataLoadedEvent, NetworkErrorEvent. Vermeiden Sie eine einzelne generische Event-Klasse mit einem String-Typ-Feld — dies eliminiert die Vorteile der Typisierung. Eine Ereignishierarchie (parent Event) ermöglicht das Abonnieren einer Gruppe verwandter Ereignisse.
// Ereignishierarchie
open class UserEvent
data class UserLoggedIn(val userId: String) : UserEvent()
data class UserLoggedOut(val reason: String) : UserEvent()
// Abonnieren der Basisklasse
class SessionManager {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onUserEvent(event: UserEvent) {
when (event) {
is UserLoggedIn -> startSession(event.userId)
is UserLoggedOut -> endSession(event.reason)
}
}
}
// Senden
EventBus.getDefault().post(UserLoggedIn("user_123"))
Der Aufruf von EventBus.getDefault().register(this) scannt die Abonnentenklasse über Reflektion oder Subscriber Index und speichert die gefundenen @Subscribe-Methoden in der Ereignis-Map. Unregister entfernt den Abonnenten aus der Map. Eine erneute Registrierung ohne Abmeldung ist ein Fehler (löst MultipleSubscriberException aus). Für Fragment registrieren Sie sich in onStart() und melden sich in onStop() ab. Für Service in onCreate() und onDestroy(). Für ViewModel wird es nicht empfohlen — verwenden Sie LiveData.
Ein sticky event ist ein Ereignis, das nach dem Senden im EventBus verbleibt. Neue nach postSticky() registrierte Abonnenten erhalten sofort das letzte sticky event des entsprechenden Typs. Dies ist praktisch zum Übergeben des Anfangszustands: Beim Öffnen eines Bildschirms erhält er die neuesten Daten, die vor seiner Registrierung gesendet wurden. Sie können ein sticky event über EventBus.getDefault().removeStickyEvent(Class) entfernen.
ThreadMode bestimmt, in welchem Thread der Handler ausgeführt wird. POSTING (Standard) — der Handler wird im selben Thread ausgeführt, in dem post aufgerufen wurde. MAIN — der Handler wird über Handler im Hauptthread ausgeführt. BACKGROUND — der Handler wird in einem Hintergrundthread ausgeführt; wenn post im Hauptthread aufgerufen wurde, stellt EventBus den Handler in eine Hintergrundthread-Warteschlange. ASYNC — jeder Handler wird in einem separaten Hintergrundthread aus einem Thread-Pool ausgeführt. Für UI-Updates verwenden Sie MAIN.
// Sticky Event
data class LocationEvent(val lat: Double, val lng: Double)
// Senden eines sticky-Ereignisses von LocationService
EventBus.getDefault().postSticky(LocationEvent(55.7558, 37.6173))
// Abonnent erhält letzten Standort sofort nach der Registrierung
class MapFragment : Fragment() {
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
// Erhält sofort LocationEvent, wenn postSticky aufgerufen wurde
}
override fun onStop() {
EventBus.getDefault().unregister(this)
super.onStop()
}
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
fun onLocationEvent(event: LocationEvent) {
moveMapTo(event.lat, event.lng)
}
}
// Entfernen eines sticky-Ereignisses
EventBus.getDefault().removeStickyEvent(LocationEvent::class.java)
BACKGROUND verwendet einen einzigen Hintergrundthread für alle Handler — sie werden sequenziell ausgeführt. ASYNC erstellt für jeden Handler einen neuen Thread aus dem Pool — sie werden parallel ausgeführt. BACKGROUND eignet sich für E/A-Operationen mit einer gemeinsamen Datenbank. ASYNC ist für unabhängige langlaufende Operationen (Netzwerkanfragen). Beide Modi erfordern threadsicheren Zugriff auf gemeinsam genutzte Ressourcen. Beachten Sie die Thread-Anzahl: Der ASYNC-Pool ist unbegrenzt.
Bei der Verwendung von EventBus machen Entwickler häufig Fehler, die zu Speicherlecks, unerwarteten Aufrufen und Leistungseinbußen führen. Am kritischsten: Vergessene Abmeldung in Activity, Registrierung in onCreate (statt onStart/onStop), Abonnieren von Object (alle Ereignisse), Senden von Ereignissen in einer Endlosschleife. Die Profilerstellung mit Android Profiler hilft, Probleme zu identifizieren.
Der häufigste Fehler ist das Registrieren einer Activity in onCreate() ohne Abmeldung in onDestroy(). Ergebnis: EventBus hält eine Referenz auf die Activity, der GC kann sie nicht freigeben. Beim Drehen des Bildschirms wird eine neue Activity erstellt, während die vorherige im Speicher bleibt. Lösung: Paaren Sie register/unregister immer in onStart/onStop. Für Fragment verwenden Sie dasselbe Muster. Wenn eine Activity nach finish von EventBus zurückgehalten wird, überprüfen Sie mit Memory Profiler.
Ohne Subscriber Index verwendet EventBus Reflektion, um @Subscribe-Methoden bei jedem register() zu finden. Auf Android 6-7-Geräten ist Reflektion langsam und verursacht Verzögerungen von bis zu 50 ms. Subscriber Index eliminiert Reflektion vollständig: Methoden werden zur Kompilierzeit über einen Annotationsprozessor indiziert. Für Projekte mit 20+ Abonnenten ist der Index obligatorisch. Stellen Sie sicher, dass kapt oder annotationProcessor in build.gradle konfiguriert ist.
// build.gradle (app) — Subscriber Index hinzufügen
dependencies {
implementation 'org.greenrobot:eventbus:3.3.1'
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.3.1'
}
// Für Kotlin kapt verwenden
plugins {
id 'kotlin-kapt'
}
dependencies {
implementation 'org.greenrobot:eventbus:3.3.1'
kapt 'org.greenrobot:eventbus-annotation-processor:3.3.1'
}
// Index-Konfiguration (in defaultConfig)
kapt {
arguments {
arg('eventBusIndex', 'com.app.EventBusIndex')
}
}
Moderne Projekte mit Kotlin und Jetpack Compose bevorzugen SharedFlow und Channel aus der kotlinx.coroutines-Bibliothek. SharedFlow unterstützt Replay (sticky), Buffering und Backpressure. Channel behandelt einmalige Ereignisse (Toast, Navigation). Beide Lösungen sind über repeatOnLifecycle in den Lifecycle integriert und erfordern keine manuelle Abmeldung. Für neue Projekte wird SharedFlow gegenüber EventBus empfohlen. Für bestehende Projekte ist eine Migration während der Refaktorierung gerechtfertigt.
Häufig gestellte Fragen
EventBus ist ein Event-Bus zum Datenaustausch zwischen beliebigen Komponenten (Activity, Fragment, Service). LiveData ist ein lifecycle-aware Wrapper für Daten, die von einer UI-Komponente beobachtet werden. LiveData verwaltet das Abonnement automatisch über den Lifecycle. EventBus erfordert manuelles register/unregister. LiveData wird für die UI-Ebene empfohlen, EventBus für modulübergreifende Kommunikation, wo LiveData unpraktisch ist.
Ein sticky event ist ein Ereignis, das nach dem Senden im EventBus verbleibt. Neue nach postSticky() registrierte Abonnenten erhalten sofort das letzte sticky event. Es wird für den Anfangszustand verwendet: Beim Öffnen eines Bildschirms erhält er die neuesten Daten ohne eine neue Anfrage. Es wird über removeStickyEvent() entfernt oder wenn ein neues sticky event desselben Typs gesendet wird.
Ja, EventBus ist threadsicher. post() kann von jedem Thread aus aufgerufen werden. Die Ereigniszustellung an Abonnenten wird intern synchronisiert. ThreadMode bestimmt den Ausführungsthread des Handlers: MAIN (Hauptthread über Handler), POSTING (Aufrufer-Thread), BACKGROUND (Hintergrundaufgabenwarteschlange), ASYNC (separater Thread). Für UI-Updates verwenden Sie MAIN. Für schwere Operationen verwenden Sie ASYNC.
Aktivieren Sie die Protokollierung über EventBus.builder().logNoSubscriberMessages(true).sendNoSubscriberEvent(true).install(). Abonnieren Sie NoSubscriberEvent, um Ereignisse ohne Handler zu verfolgen. Verwenden Sie SubscriberExceptionEvent für die globale Ausnahmebehandlung. Android Profiler hilft beim Auffinden von Lecks. Für komplexe Szenarien schreiben Sie einen Test: EventBus.getDefault().register(mock) + post(event) + verify(mock).
Nein, EventBus (GreenRobot) ist an das Android SDK und die JVM gebunden. Für Kotlin Multiplatform verwenden Sie Kotlin Multiplatform SharedFlow oder KMMBus — Bibliotheken, die gemeinsam genutzten Code unterstützen. EventBus funktioniert auf der Android-Seite eines KMM-Projekts, ist aber nicht in commonMain verfügbar. Für plattformübergreifende Ereignisse bevorzugen Sie native Plattformmechanismen oder Abstraktion über expect/actual.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch