EventBus ay isang library para sa Android na nagpapatupad ng pattern na Publisher-Subscriber sa pamamagitan ng bus ng pangyayari, na nagpapahintulot ng pagpapalitan ng data sa pagitan ng mga component nang walang direktang dependency. Binuo ng GreenRobot, pinapasimple ng library ang komunikasyon sa pagitan ng Activity, Fragment, Service at Background Thread. Ayon sa data ng GitHub (2025), ang EventBus ay may higit sa 25 libong bituin at ginagamit sa libu-libong Android application. Ang mga pangunahing operasyon ay subscribe (pag-subscribe sa pangyayari), post (pagpapadala ng pangyayari) at sticky event (naantalang pangyayari para sa mga bagong subscriber).
Mga pangunahing punto
EventBus ay isang library ng bus ng pangyayari para sa Android na nagpapatupad ng pattern na Publisher-Subscriber (tagapaglathala-taga-subscribe). Pinapayagan nito ang pagpapadala ng mga pangyayari sa pagitan ng mga component ng application (Activity, Fragment, Service, ViewModel) nang hindi lumilikha ng mga tahasang dependency sa pagitan nila. Hindi tulad ng mga karaniwang mekanismo ng Android (Intent, BroadcastReceiver), ang EventBus ay gumagana sa loob ng proseso at hindi gumagamit ng IPC. Ang library ay na-optimize para sa pagganap at hindi gumagamit ng reflection kapag ang Subscriber Index ay na-configure nang tama.
Ang arkitektura ng EventBus ay binubuo ng tatlong pangunahing elemento: Event (POJO class na may data), Subscriber(bagay na may mga pamamaraan na minarkahan ng @Subscribe) at EventBus (sentrong dispatcher). Ang subscriber ay nagrerehistro sa pamamagitan ng EventBus.getDefault().register(this), pag-unsubscribe — sa pamamagitan ng unregister(this). Ang mga pangyayari ay naka-type: ang mga tagapangasiwa ay nag-subscribe sa isang partikular na klase ng pangyayari at tinatawag lamang sa post ng pangyayari ng klase na ito o mga subklase nito.
// Pangyayaring POJO
data class MessageEvent(
val message: String,
val timestamp: Long = System.currentTimeMillis()
)
// Subscriber sa 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
}
}
// Pagpapadala ng pangyayari mula sa ibang component
EventBus.getDefault().post(MessageEvent("Hello from Service"))
Bilang default, ang EventBus ay gumagamit ng reflection upang mahanap ang mga @Subscribe na pamamaraan sa register(). Subscriber Index ay bumubuo ng index ng mga tagapangasiwa sa yugto ng compilation sa pamamagitan ng annotation processor. Ito ay nag-aalis ng overhead ng reflection at nagpapabilis ng pagrerehistro. Para i-activate, idagdag ang eventbus-annotation-processor sa build.gradle. Awtomatikong ginagamit ng EventBus ang index kung ito ay magagamit sa classpath. Kung walang index, gumagana pa rin ang library, ngunit may bahaging pagbaba ng pagganap.
Sa pagtawag ng EventBus.getDefault().post(event), tinutukoy ng library ang uri ng pangyayari, hinahanap ang lahat ng naka-rehistrong subscriber na may mga @Subscribe na pamamaraan na tumatanggap ng uri na ito, at tinatawag ang mga ito ayon sa tinukoy na ThreadMode. Ang paghahanap ng mga subscriber ay isinasagawa sa pamamagitan ng mapa Class → CopyOnWriteArrayList
Ang subscriber ay dapat magrehistro sa onStart() at mag-unsubscribe sa onStop(). Kung magrehistro sa onCreate() at mag-unsubscribe sa onDestroy(), ang Activity na nawasak nang hindi tinatawag ang onDestroy (dahil sa finish()) ay maaaring manatili sa listahan ng subscriber. Pagtagas ng subscriber — isa sa mga pangunahing problema ng EventBus: ang Activity na nananatili sa listahan ng subscriber ay hindi kokolektahin ng GC hanggang sa ito ay mag-unsubscribe. Palaging ipares ang register/unregister sa tamang lifecycle na pamamaraan.
Ang anotasyon @Subscribe ay sumusuporta sa parameter na priority (integer, default 0). Ang mga tagapangasiwa na may mas mataas na priyoridad ay tinatawag nang mas maaga. cancelEventDelivery() ay nagpapahintulot na ihinto ang paghahatid ng pangyayari sa iba pang mga subscriber. Ito ay kapaki-pakinabang para sa mga priyoridad na tagapangasiwa (pag-log, pagpapatunay) na maaaring kanselahin ang pagproseso ng pangyayari ng mga mas mababang subscriber. Ang function ay magagamit lamang sa thread ng pagpapadala ng pangyayari.
// Komplikadong halimbawa na may priyoridad
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)
}
}
// Pagpapadala ng pangyayari
EventBus.getDefault().post(NavigationEvent("profile", bundle))
Ang Android ay nag-aalok ng ilang mekanismo para sa intra-prosesong komunikasyon: EventBus, LocalBroadcastManager (luma na) at LiveData/Flow. Ang bawat isa ay may mga pakinabang at disadvantage. Ang pagpili ay depende sa arkitektural na diskarte at mga kinakailangan sa pagganap. Ang mga makabagong rekomendasyon ng Google ay pumapabor sa LiveData at Flow dahil sa integrasyon sa Lifecycle at kawalan ng mga pagtagas.
| Katangian | EventBus | LocalBroadcastManager | LiveData / Flow |
|---|---|---|---|
| Pag-type | Sa pamamagitan ng klase ng pangyayari | Sa pamamagitan ng Intent filter (String) | Sa pamamagitan ng generic na uri |
| Lifecycle-aware | Hindi (manu-manong pag-unsubscribe) | Hindi (manu-manong pag-unsubscribe) | Oo (awtomatiko) |
| Sticky | Oo (postSticky) | Hindi | Oo (LiveData — palaging sticky) |
| ThreadMode | MAIN, POSTING, BACKGROUND, ASYNC | Main lang | Sa pamamagitan ng observe/observeOn |
| Pagganap | Mataas (Subscriber Index) | Katamtaman (IPC balot) | Mataas (pagmamasid) |
Ang EventBus ay kapaki-pakinabang sa mga proyektong may legacy code at kung saan ang LiveData/Flow ay hindi magagamit (Java-only na mga proyekto). Ang Sticky events ng EventBus ay nagbibigay ng flexibility na wala sa LocalBroadcastManager. Ang EventBus ay mas simple din para sa pagpapadala ng mga pangyayari mula sa Service patungo sa Activity nang walang ViewModel — lalo na kapag kailangan mong magpaalam tungkol sa progreso ng isang background task. Ang library ay may minimal na laki (mga 50 KB) at hindi nagdaragdag ng mga dependency.
LiveData at Flow ay bahagi ng Android Jetpack at naka-integrate sa Lifecycle. Awtomatiko silang nag-unsubscribe kapag nawasak ang component, na nag-aalis ng mga pagtagas ng memorya. Ang Flow ay sumusuporta sa mga coroutine at kumplikadong operator ng transformasyon. Inirerekomenda ng Google ang LiveData para sa UI layer at Flow para sa mga repositoryo. Ang EventBus ay nananatili para sa cross-module na mga pangyayari kung saan ang nabigasyon at lohika ng negosyo ay hindi akma sa MVVM.
Subscribe — pagrerehistro ng tagapangasiwa ng pangyayari sa pamamagitan ng anotasyon @Subscribe. Ang pamamaraan ay dapat na public, void at tumanggap ng eksaktong isang parameter — ang uri ng pangyayari. Post — pagpapadala ng pangyayari sa lahat ng naka-subscribe na tagapangasiwa sa pamamagitan ng EventBus.getDefault().post(event). Ang pamamaraang post ay hindi nagbabalik ng resulta at hindi nagpapaalam kung ilang tagapangasiwa ang tinawag. Para sa mga pangyayaring may tugon, gumamit ng hiwalay na Event class na may field para sa resulta.
Ang pangyayari — anumang Java/Kotlin class. Inirerekomenda ang paggamit ng data class para sa hindi nababagong mga pangyayari at ordinaryong class para sa mga pangyayaring may mutable field. Ang pagpapangalan ng mga pangyayari ay dapat sumalamin sa aksyon: UserLoggedInEvent, DataLoadedEvent, NetworkErrorEvent. Iwasan ang isang karaniwang Event class na may String type field — inaalis nito ang mga bentahe ng pag-type. Ang hierarchy ng mga pangyayari (parent Event) ay nagpapahintulot ng pag-subscribe sa isang grupo ng mga kaugnay na pangyayari.
// Hierarkiya ng mga pangyayari
open class UserEvent
data class UserLoggedIn(val userId: String) : UserEvent()
data class UserLoggedOut(val reason: String) : UserEvent()
// Pag-subscribe sa base class
class SessionManager {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onUserEvent(event: UserEvent) {
when (event) {
is UserLoggedIn -> startSession(event.userId)
is UserLoggedOut -> endSession(event.reason)
}
}
}
// Pagpapadala
EventBus.getDefault().post(UserLoggedIn("user_123"))
Ang pagtawag sa EventBus.getDefault().register(this) ay nag-scan sa klase ng subscriber sa pamamagitan ng reflection o Subscriber Index at nag-iimbak ng mga natagpuang @Subscribe na pamamaraan sa mapa ng pangyayari. Unregister ay nag-aalis ng subscriber mula sa mapa. Ang muling pagrerehistro nang hindi nag-a-unsubscribe — error (magkakaroon ng MultipleSubscriberException). Para sa Fragment, magrehistro sa onStart() at mag-unsubscribe sa onStop(). Para sa Service — sa onCreate() at onDestroy(). Para sa ViewModel hindi inirerekomenda — gumamit ng LiveData.
Sticky event — isang pangyayari na iniimbak sa EventBus pagkatapos ipadala. Ang mga bagong subscriber na nagrehistro pagkatapos ng postSticky() ay agad na tumatanggap ng huling sticky-pangyayari ng kaukulang uri. Ito ay maginhawa para sa pagpapadala ng paunang estado: sa pagbukas ng screen, natatanggap nito ang huling data na ipinadala bago ang pagrerehistro nito. Ang pagtanggal ng sticky-pangyayari ay maaaring gawin sa pamamagitan ng EventBus.getDefault().removeStickyEvent(Class).
Tinutukoy ng ThreadMode kung saang thread tinatawag ang tagapangasiwa. POSTING (default) — ang tagapangasiwa ay isinasagawa sa parehong thread kung saan tinawag ang post. MAIN — ang tagapangasiwa ay isinasagawa sa main thread sa pamamagitan ng Handler. BACKGROUND — ang tagapangasiwa ay isinasagawa sa background thread; kung ang post ay tinawag sa main thread, inilalagay ng EventBus ang tagapangasiwa sa pila ng background thread. ASYNC — bawat tagapangasiwa ay isinasagawa sa isang hiwalay na background thread mula sa pool ng thread. Para sa mga pag-update ng UI, gamitin ang MAIN.
// Sticky Event
data class LocationEvent(val lat: Double, val lng: Double)
// Pagpapadala ng sticky-pangyayari mula sa LocationService
EventBus.getDefault().postSticky(LocationEvent(55.7558, 37.6173))
// Ang subscriber ay tumatanggap ng huling lokasyon kaagad pagkatapos ng pagrerehistro
class MapFragment : Fragment() {
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
// Kaagad makakatanggap ng LocationEvent kung may 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)
}
}
// Pagtanggal ng sticky-pangyayari
EventBus.getDefault().removeStickyEvent(LocationEvent::class.java)
BACKGROUND ay gumagamit ng isang background-thread para sa lahat ng tagapangasiwa — sila ay isinasagawa nang sunud-sunod. ASYNC ay lumilikha ng bagong thread mula sa pool para sa bawat tagapangasiwa — sila ay isinasagawa nang magkakasabay. Ang BACKGROUND ay angkop para sa mga operasyong input-output na may shared database. ASYNC — para sa mga independiyenteng mahabang operasyon (mga kahilingan sa network). Ang parehong mode ay nangangailangan ng thread-safe na access sa shared resources. Bilang ng mga thread: ang ASYNC pool ay walang limitasyon.
Sa paggamit ng EventBus, ang mga developer ay madalas nagkakamali na humahantong sa mga pagtagas ng memorya, hindi inaasahang tawag at pagbaba ng pagganap. Ang pinaka-kritikal: nakalimutang mag-unsubscribe sa Activity, pagrerehistro sa onCreate (hindi onStart/onStop), pag-subscribe sa Object (lahat ng pangyayari), pagpapadala ng mga pangyayari sa walang katapusang loop. Ang profiling sa pamamagitan ng Android Profiler ay tumutulong na makilala ang mga problema.
Ang pinakakaraniwang pagkakamali — pagrerehistro ng Activity sa onCreate() nang hindi nag-a-unsubscribe sa onDestroy(). Resulta: Ang EventBus ay nag-iimbak ng reference sa Activity, hindi ito maaaring pakawalan ng GC. Sa pag-ikot ng screen, isang bagong Activity ang nilikha, ang nauna ay nananatili sa memorya. Solusyon: palaging ipares ang register/unregister sa onStart/onStop. Para sa Fragment, gamitin ang parehong scheme. Kung ang Activity ay hawak ng EventBus pagkatapos ng finish, suriin sa pamamagitan ng Memory Profiler.
Kung walang Subscriber Index, ang EventBus ay gumagamit ng reflection upang mahanap ang mga @Subscribe na pamamaraan sa bawat register(). Sa mga device na may Android 6-7, ang reflection ay gumagana nang mabagal, na nagdudulot ng mga pagkaantala hanggang 50 ms. Ang Subscriber Index ay ganap na nag-aalis ng reflection: ang mga pamamaraan ay ini-index sa yugto ng compilation sa pamamagitan ng annotation processor. Para sa mga proyektong may 20+ subscriber, ang index ay sapilitan. Suriin kung ang kapt o annotationProcessor ay konektado sa build.gradle.
// build.gradle (app) — pagkonekta ng Subscriber Index
dependencies {
implementation 'org.greenrobot:eventbus:3.3.1'
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.3.1'
}
// Para sa Kotlin gamitin ang kapt
plugins {
id 'kotlin-kapt'
}
dependencies {
implementation 'org.greenrobot:eventbus:3.3.1'
kapt 'org.greenrobot:eventbus-annotation-processor:3.3.1'
}
// Konfigurasyon ng index (sa defaultConfig)
kapt {
arguments {
arg('eventBusIndex', 'com.app.EventBusIndex')
}
}
Ang mga makabagong proyekto sa Kotlin at Jetpack Compose ay mas pinipili ang SharedFlow at Channel mula sa library na kotlinx.coroutines. Sinusuportahan ng SharedFlow ang replay (sticky), buffering at backpressure. Channel — isang beses na mga pangyayari (toast, nabigasyon). Ang parehong solusyon ay naka-integrate sa Lifecycle sa pamamagitan ng repeatOnLifecycle at hindi nangangailangan ng manu-manong pag-unsubscribe. Para sa mga bagong proyekto, inirerekomenda ang SharedFlow sa halip na EventBus. Para sa mga umiiral na proyekto, ang migrasyon ay makatwiran sa pag-refactor.
Mga madalas itanong
EventBus ay isang bus ng pangyayari para sa pagpapalitan ng data sa pagitan ng anumang mga component (Activity, Fragment, Service). LiveData ay isang lifecycle-aware na balot para sa data na minamasdan ng isang UI component. Awtomatikong pinamamahalaan ng LiveData ang subscription sa pamamagitan ng Lifecycle. Ang EventBus ay nangangailangan ng manu-manong register/unregister. Inirerekomenda ang LiveData para sa UI layer, EventBus — para sa cross-module na komunikasyon kung saan hindi maginhawa ang LiveData.
Sticky event — isang pangyayari na iniimbak sa EventBus pagkatapos ipadala. Ang mga bagong subscriber na nagrehistro pagkatapos ng postSticky() ay agad na tumatanggap ng huling sticky-pangyayari. Ginagamit para sa paunang estado: sa pagbukas ng screen, natatanggap nito ang huling data nang walang paulit-ulit na kahilingan. Tinatanggal sa pamamagitan ng removeStickyEvent() o sa pagpapadala ng bagong sticky-pangyayari ng parehong uri.
Oo, ang EventBus ay thread-safe. Ang pagtawag ng post() ay posible mula sa anumang thread. Ang paghahatid ng pangyayari sa mga subscriber ay naka-synchronize sa loob ng library. Tinutukoy ng ThreadMode ang thread ng pagpapatupad ng tagapangasiwa: MAIN (main thread sa pamamagitan ng Handler), POSTING (thread ng nagpadala), BACKGROUND (pila ng mga background task), ASYNC (hiwalay na thread). Para sa mga pag-update ng UI gamitin ang MAIN, para sa mabibigat na operasyon — ASYNC.
I-activate ang pag-log sa pamamagitan ng EventBus.builder().logNoSubscriberMessages(true).sendNoSubscriberEvent(true).install(). Mag-subscribe sa NoSubscriberEvent para sa pagsubaybay ng mga pangyayari nang walang tagapangasiwa. Gamitin ang SubscriberExceptionEvent para sa pandaigdigang paghawak ng mga exception. Tumutulong ang Android Profiler na mahanap ang mga pagtagas. Para sa mga kumplikadong senaryo, sumulat ng test: EventBus.getDefault().register(mock) + post(event) + verify(mock).
Hindi, ang EventBus (GreenRobot) ay nakatali sa Android SDK at JVM. Para sa Kotlin Multiplatform, gamitin ang Kotlin Multiplatform SharedFlow o KMMBus — mga library na sumusuporta sa shared code. Ang EventBus sa Android side ng KMM project ay gumagana, ngunit hindi available sa commonMain. Para sa cross-platform na mga pangyayari, ang mga native na mekanismo ng platform o abstraction sa pamamagitan ng expect/actual ay mas gusto.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din