EventBus: co to je, princip fungování a událostní sběrnice Android

Autor: IT Sectr Publikováno: 2026-03-18 Doba čtení: 10 min

EventBus je knihovna pro Android implementující vzor Publisher-Subscriber pomocí událostní sběrnice, umožňující výměnu dat mezi komponentami bez přímé závislosti. Vyvinutá společností GreenRobot, knihovna zjednodušuje komunikaci mezi Activity, Fragment, Service a Background Thread. Podle údajů GitHub (2025) má EventBus více než 25 tisíc hvězdiček a používá se v tisících Android aplikací. Hlavní operace jsou subscribe (přihlášení k odběru události), post (odeslání události) a sticky event (zpožděná událost pro nové odběratele).

Hlavní body

  • EventBus — knihovna událostní sběrnice pro volně propojenou komunikaci v Android.
  • @Subscribe — anotace označující metodu jako obsluhu události určitého typu.
  • EventBus.getDefault().post() odešle událost všem přihlášeným obsluhám.
  • Sticky event uchovává poslední událost pro doručení novým odběratelům.
  • ThreadMode určuje vlákno provádění obsluhy: MAIN, POSTING, BACKGROUND, ASYNC.

Co je EventBus?

EventBus je knihovna událostní sběrnice pro Android implementující vzor Publisher-Subscriber (vydavatel-odběratel). Umožňuje přenášet události mezi komponentami aplikace (Activity, Fragment, Service, ViewModel) bez vytváření explicitních závislostí mezi nimi. Na rozdíl od standardních Android mechanismů (Intent, BroadcastReceiver) pracuje EventBus uvnitř procesu a nepoužívá IPC. Knihovna je optimalizována pro výkon a nepoužívá reflexi při správně nakonfigurovaném Subscriber Index.

GreenRobot EventBus: architektura

Architektura EventBus se skládá ze tří klíčových prvků: Event (POJO třída s daty), Subscriber (objekt s metodami označenými @Subscribe) a EventBus (centrální dispečer). Odběratel se registruje pomocí EventBus.getDefault().register(this), odhlášení — pomocí unregister(this). Události jsou typované: obsluhy se přihlašují k odběru konkrétní třídy události a jsou volány pouze při post události této třídy nebo jejích podtříd.

kotlin
// Událost POJO
data class MessageEvent(
    val message: String,
    val timestamp: Long = System.currentTimeMillis()
)

// Odběratel v 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
    }
}

// Odeslání události z jiné komponenty
EventBus.getDefault().post(MessageEvent("Hello from Service"))

Subscriber Index pro výkon

Ve výchozím nastavení EventBus používá reflexi k nalezení @Subscribe metod při register(). Subscriber Index generuje index obsluh ve fázi kompilace pomocí procesoru anotací. Tím se eliminuje režie reflexe a urychluje se registrace. Pro aktivaci přidejte eventbus-annotation-processor do build.gradle. EventBus automaticky používá index, pokud je k dispozici v classpath. Bez indexu knihovna stále funguje, ale s mírným poklesem výkonu.

Jak funguje EventBus v Android?

Při volání EventBus.getDefault().post(event) knihovna určí typ události, najde všechny registrované odběratele s metodami @Subscribe přijímajícími tento typ a zavolá je podle zadaného ThreadMode. Vyhledávání odběratelů probíhá podle mapy Class → CopyOnWriteArrayList, vytvořené při registraci. Pokud událost nemá odběratele, post skončí bez chyby — to je safe-fail chování.

Životní cyklus registrace

Odběratel by se měl zaregistrovat v onStart() a odhlásit v onStop(). Pokud se zaregistruje v onCreate() a odhlásí v onDestroy(), Activity zničená bez volání onDestroy (kvůli finish()) může zůstat v seznamu odběratelů. Únik odběratele — jeden z hlavních problémů EventBus: Activity zbývající v seznamu odběratelů nebude shromážděna GC, dokud se neodhlásí. Vždy párujte register/unregister ve správných lifecycle metodách.

Priorita obsluh

Anotace @Subscribe podporuje parametr priority (celé číslo, výchozí 0). Obsluhy s vyšší prioritou jsou volány dříve. cancelEventDelivery() umožňuje přerušit doručení události zbývajícím odběratelům. To je užitečné pro prioritní obsluhy (logování, autentizace), které mohou zrušit zpracování události nižšími odběrateli. Funkce je dostupná pouze ve vlákně odesílání události.

kotlin
// Složitý příklad s prioritou
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)
    }
}

// Odeslání události
EventBus.getDefault().post(NavigationEvent("profile", bundle))

EventBus vs LocalBroadcastManager vs LiveData

Android nabízí několik mechanismů pro vnitroprocesovou komunikaci: EventBus, LocalBroadcastManager (zastaralý) a LiveData/Flow. Každý má své výhody a nevýhody. Volba závisí na architektonickém přístupu a požadavcích na výkon. Moderní doporučení Google se přiklánějí k LiveData a Flow kvůli integraci s Lifecycle a absenci úniků.

VlastnostEventBusLocalBroadcastManagerLiveData / Flow
TypizacePomocí třídy událostiPomocí Intent filter (String)Pomocí generického typu
Lifecycle-awareNe (ruční odhlášení)Ne (ruční odhlášení)Ano (automaticky)
StickyAno (postSticky)NeAno (LiveData — vždy sticky)
ThreadModeMAIN, POSTING, BACKGROUND, ASYNCPouze mainPomocí observe/observeOn
VýkonVysoký (Subscriber Index)Střední (IPC obal)Vysoký (pozorování)

Kdy je EventBus výhodnější

EventBus je užitečný v projektech s dědictvím (legacy code) a tam, kde LiveData/Flow nejsou k dispozici (projekty Java-only). Sticky events EventBus poskytují flexibilitu, která chybí v LocalBroadcastManager. EventBus je také jednodušší pro odesílání událostí z Service do Activity bez ViewModel — zvláště když je třeba informovat o průběhu úlohy na pozadí. Knihovna má minimální velikost (asi 50 KB) a nepřidává závislosti.

Kdy jsou LiveData/Flow výhodnější

LiveData a Flow jsou součástí Android Jetpack a jsou integrovány s Lifecycle. Automaticky se odhlašují při zničení komponenty, čímž eliminují úniky paměti. Flow podporuje korutiny a složité transformační operátory. Google doporučuje LiveData pro vrstvu UI a Flow pro repozitáře. EventBus zůstává pro modulové události, kde navigace a obchodní logika nezapadají do MVVM.

Subscribe a Post: základní operace

Subscribe — registrace obsluhy události pomocí anotace @Subscribe. Metoda musí být public, void a přijímat přesně jeden parametr — typ události. Post — odeslání události všem přihlášeným obsluhám pomocí EventBus.getDefault().post(event). Metoda post nevrací výsledek a neinformuje, kolik obsluh bylo voláno. Pro události s odpovědí použijte samostatnou třídu Event s polem pro výsledek.

Vytváření vlastních událostí

Událost — libovolná třída Java/Kotlin. Doporučuje se používat data class pro neměnné události a běžnou třídu pro události s proměnnými poli. Pojmenování událostí by mělo odrážet akci: UserLoggedInEvent, DataLoadedEvent, NetworkErrorEvent. Vyhněte se jedné společné třídě Event s polem String type — to zbavuje výhod typizace. Hierarchie událostí (rodičovský Event) umožňuje přihlásit se ke skupině příbuzných událostí.

kotlin
// Hierarchie událostí
open class UserEvent
data class UserLoggedIn(val userId: String) : UserEvent()
data class UserLoggedOut(val reason: String) : UserEvent()

// Přihlášení k odběru základní třídy
class SessionManager {
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onUserEvent(event: UserEvent) {
        when (event) {
            is UserLoggedIn -> startSession(event.userId)
            is UserLoggedOut -> endSession(event.reason)
        }
    }
}

// Odeslání
EventBus.getDefault().post(UserLoggedIn("user_123"))

Registrace a odhlášení

Volání EventBus.getDefault().register(this) skenuje třídu odběratele pomocí reflexe nebo Subscriber Index a ukládá nalezené metody @Subscribe do mapy událostí. Unregister odstraňuje odběratele z mapy. Opětovná registrace bez odhlášení — chyba (dojde k MultipleSubscriberException). Pro Fragment se registrujte v onStart() a odhlašujte v onStop(). Pro Service — v onCreate() a onDestroy(). Pro ViewModel se nedoporučuje — použijte LiveData.

Sticky Events a ThreadMode

Sticky event — událost, která je po odeslání uchována v EventBus. Noví odběratelé registrovaní po postSticky() okamžitě obdrží poslední sticky-událost odpovídajícího typu. To je vhodné pro přenos počátečního stavu: při otevření obrazovky obdrží poslední data odeslaná před jeho registrací. Smazání sticky-události lze provést pomocí EventBus.getDefault().removeStickyEvent(Class).

ThreadMode: čtyři režimy provádění

ThreadMode určuje, ve kterém vlákně je obsluha volána. POSTING (výchozí) — obsluha se provádí ve stejném vlákně, kde bylo voláno post. MAIN — obsluha se provádí v main vlákně pomocí Handleru. BACKGROUND — obsluha se provádí v background vlákně; pokud bylo post voláno v main vlákně, EventBus umístí obsluhu do fronty background vlákna. ASYNC — každá obsluha se provádí v samostatném background vlákně z fondu vláken. Pro aktualizace UI použijte MAIN.

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

// Odeslání sticky-události z LocationService
EventBus.getDefault().postSticky(LocationEvent(55.7558, 37.6173))

// Odběratel obdrží poslední polohu ihned po registraci
class MapFragment : Fragment() {
    override fun onStart() {
        super.onStart()
        EventBus.getDefault().register(this)
        // Ihned obdrží LocationEvent, pokud bylo postSticky
    }

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

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

// Smazání sticky-události
EventBus.getDefault().removeStickyEvent(LocationEvent::class.java)

ThreadMode.BACKGROUND vs ASYNC

BACKGROUND používá jedno background vlákno pro všechny obsluhy — provádějí se sekvenčně. ASYNC vytváří nové vlákno z fondu pro každou obsluhu — provádějí se paralelně. BACKGROUND je vhodný pro vstupně-výstupní operace se sdílenou databází. ASYNC — pro nezávislé dlouhé operace (síťové požadavky). Oba režimy vyžadují thread-safe přístup ke sdíleným zdrojům. Počet vláken: fond ASYNC je neomezený.

Typické chyby a výkon EventBus

Při používání EventBus vývojáři často dělají chyby vedoucí k únikům paměti, neočekávaným voláním a poklesu výkonu. Nejkritičtější: zapomenuté odhlášení v Activity, registrace v onCreate (místo onStart/onStop), přihlášení k odběru Object (všechny události), odesílání událostí v nekonečné smyčce. Profilování pomocí Android Profiler pomáhá identifikovat problémy.

Úniky paměti přes EventBus

Nejčastější chyba — registrace Activity v onCreate() bez odhlášení v onDestroy(). Výsledek: EventBus uchovává referenci na Activity, GC ji nemůže uvolnit. Při otočení obrazovky se vytvoří nová Activity, předchozí zůstává v paměti. Řešení: vždy párujte register/unregister v onStart/onStop. Pro Fragment použijte stejné schéma. Pokud je Activity držena EventBus po finish, zkontrolujte pomocí Memory Profiler.

Výkon: Subscriber Index

Bez Subscriber Index EventBus používá reflexi k nalezení @Subscribe metod při každém register(). Na zařízeních s Android 6-7 reflexe pracuje pomalu, způsobuje zpoždění až 50 ms. Subscriber Index zcela eliminuje reflexi: metody jsou indexovány ve fázi kompilace pomocí procesoru anotací. Pro projekty s 20+ odběrateli je index povinný. Zkontrolujte, zda je kapt nebo annotationProcessor připojen v build.gradle.

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

// Pro Kotlin použijte kapt
plugins {
    id 'kotlin-kapt'
}

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

// Konfigurace indexu (v defaultConfig)
kapt {
    arguments {
        arg('eventBusIndex', 'com.app.EventBusIndex')
    }
}

Alternativy k EventBus v moderním Android

Moderní projekty na Kotlin a Jetpack Compose preferují SharedFlow a Channel z knihovny kotlinx.coroutines. SharedFlow podporuje replay (sticky), buffering a backpressure. Channel — jednorázové události (toast, navigace). Obě řešení jsou integrována s Lifecycle pomocí repeatOnLifecycle a nevyžadují ruční odhlášení. Pro nové projekty se doporučuje SharedFlow místo EventBus. Pro existující projekty je migrace při refaktorování opodstatněná.

Často kladené otázky

Jaký je rozdíl mezi EventBus a LiveData?

EventBus je událostní sběrnice pro výměnu dat mezi libovolnými komponentami (Activity, Fragment, Service). LiveData je lifecycle-aware obal pro data pozorovaná UI komponentou. LiveData automaticky spravuje odběr prostřednictvím Lifecycle. EventBus vyžaduje ruční register/unregister. LiveData je doporučeno pro vrstvu UI, EventBus — pro modulovou komunikaci, kde je LiveData nepohodlný.

Co je sticky event?

Sticky event — událost, která je po odeslání uchována v EventBus. Noví odběratelé registrovaní po postSticky() okamžitě obdrží poslední sticky-událost. Používá se pro počáteční stav: při otevření obrazovky obdrží poslední data bez opakovaného požadavku. Maže se pomocí removeStickyEvent() nebo při odeslání nové sticky-události stejného typu.

Je EventBus thread-safe?

Ano, EventBus je thread-safe. Volání post() je možné z libovolného vlákna. Doručení události odběratelům je synchronizováno uvnitř knihovny. ThreadMode určuje vlákno provádění obsluhy: MAIN (main vlákno přes Handler), POSTING (vlákno odesílatele), BACKGROUND (fronta úloh na pozadí), ASYNC (samostatné vlákno). Pro aktualizace UI použijte MAIN, pro těžké operace — ASYNC.

Jak ladit EventBus?

Zapněte logování pomocí EventBus.builder().logNoSubscriberMessages(true).sendNoSubscriberEvent(true).install(). Přihlaste se k odběru NoSubscriberEvent pro sledování událostí bez obsluh. Použijte SubscriberExceptionEvent pro globální zpracování výjimek. Android Profiler pomáhá najít úniky. Pro složité scénáře napište test: EventBus.getDefault().register(mock) + post(event) + verify(mock).

Lze použít EventBus v Kotlin Multiplatform?

Ne, EventBus (GreenRobot) je vázán na Android SDK a JVM. Pro Kotlin Multiplatform použijte Kotlin Multiplatform SharedFlow nebo KMMBus — knihovny podporující sdílený kód. EventBus na Android straně KMM projektu funguje, ale není dostupný v commonMain. Pro cross-platform události jsou preferovány nativní mechanismy platformy nebo abstrakce pomocí expect/actual.

Shrnutí

  • EventBus — Publisher-Subscriber knihovna pro Android, implementující událostní sběrnici s typizací pomocí POJO tříd.
  • Anotace @Subscribe s parametry threadMode, sticky, priority určuje chování obsluhy události.
  • post() odesílá událost všem odběratelům synchronně; postSticky() uchovává událost pro nové odběratele.
  • ThreadMode řídí vlákno provádění: POSTING (vlákno odesílatele), MAIN (UI), BACKGROUND (fronta), ASYNC (fond).
  • Subscriber Index procesoru anotací eliminuje reflexi a urychluje registraci.
  • Únikům paměti se předchází párováním register/unregister v onStart/onStop Activity nebo Fragment.
  • Pro nové projekty jsou preferovány SharedFlow/Channel z kotlinx.coroutines — jsou lifecycle-aware a thread-safe.

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také