EventBus: mi ez, működési elv és Android eseménybusz

Szerző: IT Sectr Megjelenés: 2026-03-18 Olvasási idő: 10 perc

EventBus egy Android könyvtár, amely a Publisher-Subscriber mintát valósítja meg egy eseménybuszon keresztül, lehetővé téve az adatcserét komponensek között közvetlen függőség nélkül. A GreenRobot által fejlesztett könyvtár leegyszerűsíti a kommunikációt az Activity, Fragment, Service és Background Thread között. A GitHub adatai szerint (2025) az EventBus több mint 25 ezer csillaggal rendelkezik, és több ezer Android alkalmazásban használják. A fő műveletek a subscribe (feliratkozás eseményre), a post (esemény küldése) és a sticky event (késleltetett esemény új feliratkozók számára).

Főbb pontok

  • EventBus — eseménybusz könyvtár laza kapcsolódású kommunikációhoz Android-ban.
  • @Subscribe — annotáció, amely egy metódust egy adott típusú esemény kezelőjeként jelöl meg.
  • EventBus.getDefault().post() elküldi az eseményt az összes feliratkozott kezelőnek.
  • Sticky event megőrzi az utolsó eseményt az új feliratkozók számára történő kézbesítéshez.
  • ThreadMode meghatározza a kezelő végrehajtási szálát: MAIN, POSTING, BACKGROUND, ASYNC.

Mi az EventBus?

EventBus egy eseménybusz könyvtár Android-hoz, amely a Publisher-Subscriber (kiadó-feliratkozó) mintát valósítja meg. Lehetővé teszi események továbbítását az alkalmazás komponensei (Activity, Fragment, Service, ViewModel) között anélkül, hogy explicit függőségeket hozna létre közöttük. Ellentétben a szabványos Android mechanizmusokkal (Intent, BroadcastReceiver), az EventBus a folyamaton belül működik, és nem használ IPC-t. A könyvtár teljesítményre van optimalizálva, és nem használ reflexiót, ha a Subscriber Index megfelelően van konfigurálva.

GreenRobot EventBus: architektúra

Az EventBus architektúrája három kulcselemből áll: Event (POJO osztály adatokkal), Subscriber (objektum @Subscribe jelölt metódusokkal) és EventBus (központi diszpécser). A feliratkozó az EventBus.getDefault().register(this) segítségével regisztrál, a leiratkozás az unregister(this) segítségével történik. Az események típusosak: a kezelők egy adott eseményosztályra iratkoznak fel, és csak az adott osztály vagy alosztályai eseményének post-olásakor hívódnak meg.

kotlin
// POJO esemény
data class MessageEvent(
    val message: String,
    val timestamp: Long = System.currentTimeMillis()
)

// Feliratkozó Activity-ben
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
    }
}

// Esemény küldése másik komponensből
EventBus.getDefault().post(MessageEvent("Hello from Service"))

Subscriber Index a teljesítményért

Alapértelmezés szerint az EventBus reflexiót használ a @Subscribe metódusok megtalálásához a register()-nél. Subscriber Index a fordítási fázisban generál egy indexet a kezelőkről egy annotáció-feldolgozó segítségével. Ez megszünteti a reflexió többletterhelését és felgyorsítja a regisztrációt. Az aktiváláshoz adja hozzá az eventbus-annotation-processor-t a build.gradle-hez. Az EventBus automatikusan használja az indexet, ha az elérhető a classpath-ban. Index nélkül a könyvtár továbbra is működik, de enyhe teljesítménycsökkenéssel.

Hogyan működik az EventBus Android-ban?

Az EventBus.getDefault().post(event) meghívásakor a könyvtár meghatározza az esemény típusát, megkeresi az összes regisztrált feliratkozót @Subscribe metódusokkal, amelyek elfogadják ezt a típust, és meghívja őket a megadott ThreadMode szerint. A feliratkozók keresése a Class → CopyOnWriteArrayList térkép alapján történik, amely a regisztráció során épül fel. Ha az eseménynek nincs feliratkozója, a post hiba nélkül befejeződik — ez safe-fail viselkedés.

A regisztráció életciklusa

A feliratkozónak onStart()-ban kell regisztrálnia és onStop()-ban leiratkoznia. Ha onCreate()-ban regisztrál és onDestroy()-ban iratkozik le, az onDestroy meghívása nélkül megsemmisült Activity (a finish() miatt) a feliratkozók listáján maradhat. Feliratkozó szivárgás — az EventBus egyik fő problémája: a feliratkozók listáján maradt Activity-t a GC nem gyűjti be, amíg le nem iratkozik. Mindig párosítsa a register/unregister-t a megfelelő lifecycle metódusokban.

Kezelők prioritása

A @Subscribe annotáció támogatja a priority paramétert (egész szám, alapértelmezett 0). A magasabb prioritású kezelők korábban hívódnak meg. cancelEventDelivery() lehetővé teszi az esemény további feliratkozókhoz történő kézbesítésének megszakítását. Ez hasznos a prioritásos kezelőknél (naplózás, hitelesítés), amelyek megszakíthatják az esemény feldolgozását az alacsonyabb feliratkozók által. A funkció csak az esemény küldési szálában érhető el.

kotlin
// Komplex példa prioritással
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)
    }
}

// Esemény küldése
EventBus.getDefault().post(NavigationEvent("profile", bundle))

EventBus vs LocalBroadcastManager vs LiveData

Az Android több mechanizmust kínál a folyamaton belüli kommunikációhoz: EventBus, LocalBroadcastManager (elavult) és LiveData/Flow. Mindegyiknek megvannak az előnyei és hátrányai. A választás az architekturális megközelítéstől és a teljesítménykövetelményektől függ. A Google modern ajánlásai a LiveData és Flow felé hajlanak a Lifecycle integráció és a szivárgások hiánya miatt.

JellemzőEventBusLocalBroadcastManagerLiveData / Flow
TípusosságEseményosztályon keresztülIntent filter (String) általGenerikus típus által
Lifecycle-awareNem (manuális leiratkozás)Nem (manuális leiratkozás)Igen (automatikus)
StickyIgen (postSticky)NemIgen (LiveData — mindig sticky)
ThreadModeMAIN, POSTING, BACKGROUND, ASYNCCsak mainobserve/observeOn által
TeljesítményMagas (Subscriber Index)Közepes (IPC csomagolás)Magas (megfigyelés)

Mikor előnyösebb az EventBus

Az EventBus hasznos örökölt kóddal rendelkező projektekben (legacy code) és ahol a LiveData/Flow nem elérhető (Java-only projektek). Az EventBus Sticky events funkciója olyan rugalmasságot nyújt, ami hiányzik a LocalBroadcastManager-ből. Az EventBus egyszerűbb az események Service-ből Activity-be küldésére ViewModel nélkül — különösen, amikor egy háttérfeladat előrehaladásáról kell értesíteni. A könyvtár minimális méretű (körülbelül 50 KB) és nem ad hozzá függőségeket.

Mikor előnyösebb a LiveData/Flow

LiveData és Flow az Android Jetpack részét képezik, és integrálva vannak a Lifecycle-lel. Automatikusan leiratkoznak a komponens megsemmisülésekor, kiküszöbölve a memóriaszivárgásokat. A Flow támogatja a korutinokat és az összetett transzformációs operátorokat. A Google a LiveData-t ajánlja az UI réteghez, a Flow-t pedig a repository-khoz. Az EventBus a modulok közötti eseményekre marad, ahol a navigáció és az üzleti logika nem illeszkedik az MVVM-be.

Subscribe és Post: alapműveletek

Subscribe — eseménykezelő regisztrációja a @Subscribe annotáción keresztül. A metódusnak public, void típusúnak kell lennie, és pontosan egy paramétert kell fogadnia — az esemény típusát. Post — esemény küldése az összes feliratkozott kezelőnek az EventBus.getDefault().post(event) segítségével. A post metódus nem ad vissza eredményt, és nem tájékoztat arról, hogy hány kezelő lett meghívva. Választ igénylő eseményekhez használjon külön Event osztályt egy eredmény mezővel.

Egyedi események létrehozása

Az esemény bármely Java/Kotlin osztály lehet. Javasolt data class használata megváltoztathatatlan eseményekhez és sima osztály a mutable mezőkkel rendelkező eseményekhez. Az események elnevezésének tükröznie kell a műveletet: UserLoggedInEvent, DataLoadedEvent, NetworkErrorEvent. Kerülje az egy közös Event osztályt String type mezővel — ez megfosztja a típusosság előnyeitől. Az események hierarchiája (szülő Event) lehetővé teszi a kapcsolódó események csoportjára való feliratkozást.

kotlin
// Események hierarchiája
open class UserEvent
data class UserLoggedIn(val userId: String) : UserEvent()
data class UserLoggedOut(val reason: String) : UserEvent()

// Feliratkozás alaposztályra
class SessionManager {
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onUserEvent(event: UserEvent) {
        when (event) {
            is UserLoggedIn -> startSession(event.userId)
            is UserLoggedOut -> endSession(event.reason)
        }
    }
}

// Küldés
EventBus.getDefault().post(UserLoggedIn("user_123"))

Regisztráció és leiratkozás

Az EventBus.getDefault().register(this) hívása beolvassa a feliratkozó osztályát reflexió vagy Subscriber Index segítségével, és eltárolja a talált @Subscribe metódusokat az eseménytérképben. Unregister eltávolítja a feliratkozót a térképből. Újraregisztráció leiratkozás nélkül — hiba (MultipleSubscriberException lép fel). Fragment esetén regisztráljon onStart()-ban és iratkozzon le onStop()-ban. Service esetén — onCreate()-ban és onDestroy()-ban. ViewModel esetén nem ajánlott — használjon LiveData-t.

Sticky Events és ThreadMode

Sticky event — egy esemény, amely elküldés után megőrződik az EventBus-ban. A postSticky() után regisztráló új feliratkozók azonnal megkapják a megfelelő típusú utolsó sticky-eseményt. Ez kényelmes a kezdeti állapot továbbításához: a képernyő megnyitásakor megkapja a regisztráció előtt elküldött utolsó adatokat. A sticky-esemény törlése az EventBus.getDefault().removeStickyEvent(Class) segítségével lehetséges.

ThreadMode: négy végrehajtási mód

A ThreadMode meghatározza, hogy a kezelő melyik szálban hívódik meg. POSTING (alapértelmezett) — a kezelő ugyanabban a szálban hajtódik végre, ahol a post-ot meghívták. MAIN — a kezelő a main szálban hajtódik végre Handler segítségével. BACKGROUND — a kezelő background szálban hajtódik végre; ha a post-ot main szálban hívták meg, az EventBus a kezelőt a background szál sorába helyezi. ASYNC — minden kezelő egy külön background szálban hajtódik végre a szálkészletből. UI frissítésekhez használja a MAIN-t.

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

// Sticky-esemény küldése a LocationService-ből
EventBus.getDefault().postSticky(LocationEvent(55.7558, 37.6173))

// A feliratkozó azonnal megkapja az utolsó helyadatot a regisztráció után
class MapFragment : Fragment() {
    override fun onStart() {
        super.onStart()
        EventBus.getDefault().register(this)
        // Azonnal megkapja a LocationEvent-et, ha volt 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)
    }
}

// Sticky-esemény törlése
EventBus.getDefault().removeStickyEvent(LocationEvent::class.java)

ThreadMode.BACKGROUND vs ASYNC

BACKGROUND egy background szálat használ az összes kezelő számára — egymás után hajtódnak végre. ASYNC új szálat hoz létre a készletből minden kezelő számára — párhuzamosan hajtódnak végre. A BACKGROUND alkalmas bemeneti-kimeneti műveletekhez megosztott adatbázissal. ASYNC — független hosszú műveletekhez (hálózati kérések). Mindkét mód thread-safe hozzáférést igényel a megosztott erőforrásokhoz. Szálak száma: az ASYNC készlet korlátlan.

Gyakori hibák és az EventBus teljesítménye

Az EventBus használatakor a fejlesztők gyakran követnek el hibákat, amelyek memóriaszivárgáshoz, váratlan hívásokhoz és teljesítménycsökkenéshez vezetnek. A legkritikusabbak: elfelejtett leiratkozás Activity-ben, regisztráció onCreate-ban (nem onStart/onStop), feliratkozás Object-re (minden esemény), események küldése végtelen ciklusban. Az Android Profiler segítségével történő profilozás segít a problémák azonosításában.

Memóriaszivárgás az EventBus-on keresztül

A leggyakoribb hiba — Activity regisztrációja onCreate()-ban anélkül, hogy leiratkozna onDestroy()-ban. Eredmény: Az EventBus referenciát tart az Activity-re, a GC nem tudja felszabadítani. A képernyő elforgatásakor új Activity jön létre, az előző a memóriában marad. Megoldás: mindig párosítsa a register/unregister-t onStart/onStop-ban. Fragment esetén használja ugyanazt a sémát. Ha az Activity-t az EventBus a finish után is megtartja, ellenőrizze a Memory Profiler segítségével.

Teljesítmény: Subscriber Index

Subscriber Index nélkül az EventBus reflexiót használ a @Subscribe metódusok megtalálásához minden register()-nél. Android 6-7 eszközökön a reflexió lassan működik, akár 50 ms késleltetést okozva. A Subscriber Index teljesen megszünteti a reflexiót: a metódusok a fordítási fázisban indexelődnek egy annotáció-feldolgozó segítségével. 20+ feliratkozóval rendelkező projekteknél az index kötelező. Ellenőrizze, hogy a kapt vagy annotationProcessor csatlakoztatva van-e a build.gradle-ben.

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

// Kotlin esetén használjon kapt-ot
plugins {
    id 'kotlin-kapt'
}

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

// Az index konfigurációja (defaultConfig-ban)
kapt {
    arguments {
        arg('eventBusIndex', 'com.app.EventBusIndex')
    }
}

Az EventBus alternatívái a modern Android-ban

A Kotlin és Jetpack Compose alapú modern projektek a SharedFlow és Channel használatát részesítik előnyben a kotlinx.coroutines könyvtárból. A SharedFlow támogatja a replay (sticky), buffering és backpressure funkciókat. A Channel — egyszeri eseményeket (toast, navigáció). Mindkét megoldás integrálva van a Lifecycle-lel a repeatOnLifecycle segítségével, és nem igényel manuális leiratkozást. Új projektekhez a SharedFlow ajánlott az EventBus helyett. Meglévő projekteknél a migráció refaktoráláskor indokolt.

Gyakran ismételt kérdések

Mi a különbség az EventBus és a LiveData között?

EventBus egy eseménybusz az adatcseréhez bármely komponens között (Activity, Fragment, Service). LiveData egy lifecycle-aware csomagoló az UI komponens által megfigyelt adatokhoz. A LiveData automatikusan kezeli a feliratkozást a Lifecycle-en keresztül. Az EventBus manuális register/unregister-t igényel. A LiveData az UI réteghez ajánlott, az EventBus — a modulok közötti kommunikációhoz, ahol a LiveData kényelmetlen.

Mi az a sticky event?

Sticky event — egy esemény, amely elküldés után megőrződik az EventBus-ban. A postSticky() után regisztráló új feliratkozók azonnal megkapják az utolsó sticky-eseményt. A kezdeti állapothoz használják: a képernyő megnyitásakor megkapja az utolsó adatokat ismételt kérés nélkül. Törlése a removeStickyEvent() segítségével vagy új sticky-esemény elküldésekor történik.

Az EventBus thread-safe?

Igen, az EventBus thread-safe. A post() hívása bármely szálból lehetséges. Az esemény feliratkozókhoz történő kézbesítése a könyvtáron belül szinkronizálódik. A ThreadMode meghatározza a kezelő végrehajtási szálát: MAIN (main szál Handler-en keresztül), POSTING (küldő szál), BACKGROUND (háttérfeladatok sora), ASYNC (külön szál). UI frissítésekhez használja a MAIN-t, nehéz műveletekhez — ASYNC-et.

Hogyan lehet debug-olni az EventBus-t?

Kapcsolja be a naplózást a EventBus.builder().logNoSubscriberMessages(true).sendNoSubscriberEvent(true).install() segítségével. Iratkozzon fel a NoSubscriberEvent-re a kezelő nélküli események nyomon követéséhez. Használja a SubscriberExceptionEvent-t a globális kivételkezeléshez. Az Android Profiler segít a szivárgások megtalálásában. Összetett forgatókönyvekhez írjon tesztet: EventBus.getDefault().register(mock) + post(event) + verify(mock).

Használható az EventBus Kotlin Multiplatform-ban?

Nem, az EventBus (GreenRobot) az Android SDK-hoz és JVM-hez van kötve. Kotlin Multiplatform-hoz használja a Kotlin Multiplatform SharedFlow vagy KMMBus — a megosztott kódot támogató könyvtárakat. Az EventBus a KMM projekt Android oldalán működik, de nem érhető el a commonMain-ben. A cross-platform eseményekhez a platform natív mechanizmusai vagy az expect/actual segítségével történő absztrakció előnyösebb.

Összefoglalás

  • EventBus — Publisher-Subscriber könyvtár Android-hoz, amely eseménybusz-t valósít meg POJO osztályokon keresztüli típusossággal.
  • A @Subscribe annotáció a threadMode, sticky, priority paraméterekkel meghatározza az eseménykezelő viselkedését.
  • post() szinkronban küldi el az eseményt az összes feliratkozónak; postSticky() megőrzi az eseményt új feliratkozók számára.
  • ThreadMode kezeli a végrehajtási szálat: POSTING (küldő szál), MAIN (UI), BACKGROUND (sor), ASYNC (készlet).
  • Az annotáció-feldolgozó Subscriber Index megszünteti a reflexiót és felgyorsítja a regisztrációt.
  • A memóriaszivárgások megelőzhetők a register/unregister párosításával onStart/onStop Activity vagy Fragment esetén.
  • Új projektekhez a kotlinx.coroutines SharedFlow/Channel javasolt — ezek lifecycle-aware és thread-safe.

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is