EventBus Android üçün kitabxanadır, Publisher-Subscriber nümunəsini hadisə avtobusu vasitəsilə tətbiq edir və komponentlər arasında birbaşa asılılıq olmadan məlumat mübadiləsinə imkan verir. GreenRobot tərəfindən hazırlanmış kitabxana Activity, Fragment, Service və Background Thread arasında kommunikasiyanı sadələşdirir. GitHub məlumatlarına görə (2025), EventBus 25 mindən çox ulduza malikdir və minlərlə Android tətbiqində istifadə olunur. Əsas əməliyyatlar — subscribe (hadisəyə abunə olma), post (hadisə göndərmə) və sticky event (yeni abunəçilər üçün təxirə salınmış hadisə).
Əsas məqamlar
EventBus Android üçün hadisə avtobusu kitabxanasıdır, Publisher-Subscriber (nəşr edən-abunə olan) nümunəsini tətbiq edir. Tətbiq komponentləri (Activity, Fragment, Service, ViewModel) arasında onlar arasında açıq asılılıqlar yaratmadan hadisələr ötürməyə imkan verir. Standart Android mexanizmlərindən (Intent, BroadcastReceiver) fərqli olaraq, EventBus proses daxilində işləyir və IPC istifadə etmir. Kitabxana performans üçün optimallaşdırılıb və Subscriber Index düzgün konfiqurasiya edildikdə refleksiyadan istifadə etmir.
EventBus arxitekturası üç əsas elementdən ibarətdir: Event (məlumatlarla POJO sinfi), Subscriber (@Subscribe ilə qeyd olunmuş metodları olan obyekt) və EventBus (mərkəzi dispetçer). Abunəçi EventBus.getDefault().register(this) vasitəsilə qeydiyyatdan keçir, unregister(this) ilə çıxarılır. Hadisələr tipləşdirilmişdir: işləyicilər konkret hadisə sinfinə abunə olur və yalnız bu sinfin və ya alt siniflərinin hadisəsi post edildikdə çağırılır.
// POJO hadisəsi
data class MessageEvent(
val message: String,
val timestamp: Long = System.currentTimeMillis()
)
// Activity-də abunəçi
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
}
}
// Hadisənin başqa komponentdən göndərilməsi
EventBus.getDefault().post(MessageEvent("Hello from Service"))
Varsayılan olaraq EventBus register() zamanı @Subscribe metodlarını tapmaq üçün refleksiyadan istifadə edir. Subscriber Index annotasiya prosessoru vasitəsilə kompilyasiya mərhələsində işləyicilərin indeksini yaradır. Bu refleksiya yükünü aradan qaldırır və qeydiyyatı sürətləndirir. Aktivləşdirmək üçün build.gradle-a eventbus-annotation-processor əlavə edin. EventBus classpath-da mövcud olduqda indeksi avtomatik istifadə edir. İndeks olmadan kitabxana hələ də işləyir, lakin bir qədər aşağı performansla.
EventBus.getDefault().post(event) çağırıldıqda kitabxana hadisənin tipini müəyyən edir, bu tipi qəbul edən @Subscribe metodları olan bütün qeydiyyatdan keçmiş abunəçiləri tapır və onları göstərilən ThreadMode-a uyğun çağırır. Abunəçilərin axtarışı qeydiyyat zamanı qurulmuş Class → CopyOnWriteArrayList
Abunəçi onStart()-da qeydiyyatdan keçməli və onStop()-da qeydiyyatdan çıxmalıdır. onCreate()-də qeydiyyatdan keçib onDestroy()-də çıxarsa, onDestroy çağırılmadan məhv edilmiş Activity (finish() səbəbindən) abunəçilər siyahısında qala bilər. Abunəçi sızması — EventBus-un əsas problemlərindən biri: abunəçilər siyahısında qalan Activity qeydiyyatdan çıxana qədər GC tərəfindən yığılmayacaq. Həmişə register/unregister-ı düzgün lifecycle metodlarında birləşdirin.
@Subscribe annotasiyası priority parametrini dəstəkləyir (tam ədəd, varsayılan 0). Daha yüksək prioritetli işləyicilər daha əvvəl çağırılır. cancelEventDelivery() hadisənin qalan abunəçilərə çatdırılmasını dayandırmağa imkan verir. Bu, prioritet işləyicilər (loqlama, autentifikasiya) üçün faydalıdır, onlar aşağıdakı abunəçilər tərəfindən hadisənin işlənməsini ləğv edə bilər. Funksiya yalnız hadisə göndərmə threadində mövcuddur.
// Prioritetli mürəkkəb nümunə
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)
}
}
// Hadisənin göndərilməsi
EventBus.getDefault().post(NavigationEvent("profile", bundle))
Android daxili proses kommunikasiyası üçün bir neçə mexanizm təklif edir: EventBus, LocalBroadcastManager (köhnəlmiş) və LiveData/Flow. Hər birinin üstünlükləri və çatışmazlıqları var. Seçim arxitektura yanaşmasından və performans tələblərindən asılıdır. Google-un müasir tövsiyələri Lifecycle ilə inteqrasiya və sızmaların olmaması səbəbindən LiveData və Flow-a meyllidir.
| Xüsusiyyət | EventBus | LocalBroadcastManager | LiveData / Flow |
|---|---|---|---|
| Tipləşdirmə | Hadisə sinfi vasitəsilə | Intent filter (String) vasitəsilə | Generic tip vasitəsilə |
| Lifecycle-aware | Xeyr (əl ilə çıxarılma) | Xeyr (əl ilə çıxarılma) | Bəli (avtomatik) |
| Sticky | Bəli (postSticky) | Xeyr | Bəli (LiveData — həmişə sticky) |
| ThreadMode | MAIN, POSTING, BACKGROUND, ASYNC | Yalnız main | observe/observeOn vasitəsilə |
| Performans | Yüksək (Subscriber Index) | Orta (IPC qablaşdırması) | Yüksək (müşahidə) |
EventBus böyük irsə malik layihələrdə (legacy code) və LiveData/Flow-un əlçatan olmadığı yerlərdə (Java-only layihələri) faydalıdır. EventBus-un Sticky events-i LocalBroadcastManager-də olmayan elastiklik verir. EventBus həmçinin ViewModel olmadan Service-dən Activity-ə hadisələr göndərmək üçün daha sadədir — xüsusən fon tapşırığının gedişatı barədə xəbərdar etmək lazım olduqda. Kitabxana minimal ölçüyə malikdir (təxminən 50 KB) və asılılıq əlavə etmir.
LiveData və Flow Android Jetpack-in bir hissəsidir və Lifecycle ilə inteqrasiya olunub. Komponent məhv olduqda avtomatik olaraq abunəlikdən çıxır, yaddaş sızmalarını aradan qaldırır. Flow korutinləri və mürəkkəb transformasiya operatorlarını dəstəkləyir. Google LiveData-nı UI təbəqəsi üçün, Flow-u isə repozitoriyalar üçün tövsiyə edir. EventBus naviqasiya və biznes məntiqinin MVVM-ə uyğun gəlmədiyi cross-modul hadisələr üçün qalır.
Subscribe — @Subscribe annotasiyası vasitəsilə hadisə işləyicisinin qeydiyyatı. Metod public, void olmalı və tam bir parametr qəbul etməlidir — hadisə tipi. Post — EventBus.getDefault().post(event) vasitəsilə hadisənin bütün abunə olmuş işləyicilərə göndərilməsi. Post metodu nəticə qaytarmır və neçə işləyicinin çağırıldığı barədə məlumat vermir. Cavab tələb edən hadisələr üçün nəticə sahəsi olan ayrıca Event sinfi istifadə edin.
Hadisə — istənilən Java/Kotlin sinfidir. Dəyişməz hadisələr üçün data class, mutable sahələri olan hadisələr üçün adi sinif istifadə etmək tövsiyə olunur. Hadisələrin adlandırılması hərəkəti əks etdirməlidir: UserLoggedInEvent, DataLoadedEvent, NetworkErrorEvent. String type sahəsi olan ümumi Event sinfindən çəkinin — bu tipləşdirmənin üstünlüklərini itirir. Hadisələr iyerarxiyası (ana Event) qohum hadisələr qrupuna abunə olmağa imkan verir.
// Hadisələr iyerarxiyası
open class UserEvent
data class UserLoggedIn(val userId: String) : UserEvent()
data class UserLoggedOut(val reason: String) : UserEvent()
// Baza sinfinə abunəlik
class SessionManager {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onUserEvent(event: UserEvent) {
when (event) {
is UserLoggedIn -> startSession(event.userId)
is UserLoggedOut -> endSession(event.reason)
}
}
}
// Göndərmə
EventBus.getDefault().post(UserLoggedIn("user_123"))
EventBus.getDefault().register(this) çağırışı abunəçinin sinfini refleksiya və ya Subscriber Index vasitəsilə skan edir və tapılan @Subscribe metodlarını hadisə xəritəsində saxlayır. Unregister abunəçini xəritədən silir. Qeydiyyatdan çıxmadan təkrar qeydiyyat — xətadır (MultipleSubscriberException olacaq). Fragment üçün onStart()-da qeydiyyatdan keçin və onStop()-da çıxın. Service üçün — onCreate()-də və onDestroy()-də. ViewModel üçün tövsiyə edilmir — LiveData istifadə edin.
Sticky event — göndərildikdən sonra EventBus-da saxlanılan hadisədir. postSticky()-dən sonra qeydiyyatdan keçən yeni abunəçilər dərhal müvafiq tipin son sticky-hadisəsini alırlar. Bu, ilkin vəziyyəti ötürmək üçün rahatdır: ekran açıldıqda qeydiyyatından əvvəl göndərilmiş son məlumatları alır. Sticky-hadisəni EventBus.getDefault().removeStickyEvent(Class) vasitəsilə silmək olar.
ThreadMode işləyicinin hansı threaddə çağırılacağını təyin edir. POSTING (varsayılan) — işləyici post-un çağırıldığı eyni threaddə icra olunur. MAIN — işləyici main thread-də Handler vasitəsilə icra olunur. BACKGROUND — işləyici background thread-də icra olunur; əgər post main thread-də çağırılıbsa, EventBus işləyicini background thread növbəsinə yerləşdirir. ASYNC — hər bir işləyici thread hovuzundan ayrıca background thread-də icra olunur. UI yeniləmələri üçün MAIN istifadə edin.
// Sticky Event
data class LocationEvent(val lat: Double, val lng: Double)
// LocationService-dən sticky-hadisənin göndərilməsi
EventBus.getDefault().postSticky(LocationEvent(55.7558, 37.6173))
// Abunəçi qeydiyyatdan dərhal sonra son yerləşməni alır
class MapFragment : Fragment() {
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
// postSticky olubsa dərhal LocationEvent alacaq
}
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-hadisənin silinməsi
EventBus.getDefault().removeStickyEvent(LocationEvent::class.java)
BACKGROUND bütün işləyicilər üçün bir background thread istifadə edir — onlar ardıcıl icra olunur. ASYNC hər bir işləyici üçün hovuzdan yeni thread yaradır — onlar paralel icra olunur. BACKGROUND ortaq verilənlər bazası ilə giriş-çıxış əməliyyatları üçün uyğundur. ASYNC — müstəqil uzun əməliyyatlar üçün (şəbəkə sorğuları). Hər iki rejim ortaq resurslara thread-safe giriş tələb edir. Thread sayı: ASYNC hovuzu limitsizdir.
EventBus istifadə edərkən tərtibatçılar tez-tez yaddaş sızmalarına, gözlənilməz çağırışlara və performansın düşməsinə səbəb olan səhvlərə yol verirlər. Ən kritik olanlar: Activity-də unudulmuş qeydiyyatdan çıxma, onCreate-də qeydiyyat (onStart/onStop əvəzinə), Object-ə abunəlik (bütün hadisələr), sonsuz dövrədə hadisələr göndərmək. Android Profiler vasitəsilə profilinq problemləri aşkarlamağa kömək edir.
Ən geniş yayılmış səhv — onDestroy()-də qeydiyyatdan çıxmadan onCreate()-də Activity-nin qeydiyyatı. Nəticə: EventBus Activity-yə istinad saxlayır, GC onu boşada bilmir. Ekran döndərildikdə yeni Activity yaradılır, əvvəlki yaddaşda qalır. Həll yolu: həmişə register/unregister-ı onStart/onStop-da birləşdirin. Fragment üçün eyni sxemdən istifadə edin. Əgər Activity EventBus tərəfindən finish-dən sonra saxlanılırsa, Memory Profiler vasitəsilə yoxlayın.
Subscriber Index olmadan EventBus hər register() zamanı @Subscribe metodlarını tapmaq üçün refleksiyadan istifadə edir. Android 6-7 cihazlarında refleksiya yavaş işləyir, 50 ms-ə qədər gecikmələrə səbəb olur. Subscriber Index refleksiyanı tamamilə aradan qaldırır: metodlar annotation prosessoru vasitəsilə kompilyasiya mərhələsində indekslənir. 20+ abunəçisi olan layihələr üçün indeks məcburidir. build.gradle-da kapt və ya annotationProcessor-un qoşulduğunu yoxlayın.
// build.gradle (app) — Subscriber Index-in qoşulması
dependencies {
implementation 'org.greenrobot:eventbus:3.3.1'
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.3.1'
}
// Kotlin üçün kapt istifadə edin
plugins {
id 'kotlin-kapt'
}
dependencies {
implementation 'org.greenrobot:eventbus:3.3.1'
kapt 'org.greenrobot:eventbus-annotation-processor:3.3.1'
}
// İndeksin konfiqurasiyası (defaultConfig-də)
kapt {
arguments {
arg('eventBusIndex', 'com.app.EventBusIndex')
}
}
Kotlin və Jetpack Compose-da müasir layihələr kotlinx.coroutines kitabxanasından SharedFlow və Channel-ə üstünlük verir. SharedFlow replay (sticky), buffering və backpressure dəstəkləyir. Channel — birdəfəlik hadisələr (toast, naviqasiya). Hər iki həll repeatOnLifecycle vasitəsilə Lifecycle ilə inteqrasiya olunub və əl ilə qeydiyyatdan çıxarma tələb etmir. Yeni layihələr üçün EventBus əvəzinə SharedFlow tövsiyə olunur. Mövcud layihələr üçün miqrasiya refaktoring zamanı məqsədəuyğundur.
Tez-tez verilən suallar
EventBus istənilən komponentlər (Activity, Fragment, Service) arasında məlumat mübadiləsi üçün hadisə avtobusudur. LiveData UI komponenti tərəfindən müşahidə edilən məlumatlar üçün lifecycle-aware qablaşdırmadır. LiveData Lifecycle vasitəsilə abunəliyi avtomatik idarə edir. EventBus əl ilə register/unregister tələb edir. LiveData UI təbəqəsi üçün tövsiyə olunur, EventBus — LiveData-nın əlverişsiz olduğu cross-modul kommunikasiya üçün.
Sticky event — göndərildikdən sonra EventBus-da saxlanılan hadisədir. postSticky()-dən sonra qeydiyyatdan keçən yeni abunəçilər dərhal son sticky-hadisəni alırlar. İlkin vəziyyət üçün istifadə olunur: ekran açıldıqda təkrar sorğu olmadan son məlumatları alır. removeStickyEvent() və ya eyni tipdə yeni sticky-hadisə göndərildikdə silinir.
Bəli, EventBus thread-safe-dir. post() çağırışı istənilən thread-dən mümkündür. Hadisənin abunəçilərə çatdırılması kitabxana daxilində sinxronlaşdırılır. ThreadMode işləyicinin icra threadini təyin edir: MAIN (main thread Handler vasitəsilə), POSTING (göndərənin threadi), BACKGROUND (fon tapşırıqları növbəsi), ASYNC (ayrıca thread). UI yeniləmələri üçün MAIN, ağır əməliyyatlar üçün ASYNC istifadə edin.
EventBus.builder().logNoSubscriberMessages(true).sendNoSubscriberEvent(true).install() vasitəsilə loqlamağı aktivləşdirin. İşləyicisi olmayan hadisələri izləmək üçün NoSubscriberEvent-ə abunə olun. Qlobal istisna idarəetməsi üçün SubscriberExceptionEvent istifadə edin. Android Profiler sızmaları tapmağa kömək edir. Mürəkkəb ssenarilər üçün test yazın: EventBus.getDefault().register(mock) + post(event) + verify(mock).
Xeyr, EventBus (GreenRobot) Android SDK və JVM-ə bağlıdır. Kotlin Multiplatform üçün Kotlin Multiplatform SharedFlow və ya KMMBus — ortaq kodu dəstəkləyən kitabxanalardan istifadə edin. EventBus KMM layihəsinin Android tərəfində işləyir, lakin commonMain-də əlçatan deyil. Cross-platform hadisələr üçün platformanın native mexanizmləri və ya expect/actual vasitəsilə abstraksiya daha üstündür.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun