EventBus, bir olay veriyolu aracılığıyla Publisher-Subscriber modelini uygulayan ve bileşenler arasında doğrudan bağımlılık olmadan veri alışverişine izin veren bir Android kütüphanesidir. GreenRobot tarafından geliştirilen kütüphane, Activity, Fragment, Service ve Background Thread arasındaki iletişimi basitleştirir. GitHub verilerine (2025) göre EventBus, 25 binden fazla yıldıza sahiptir ve binlerce Android uygulamasında kullanılmaktadır. Ana işlemler subscribe (bir olaya abone olma), post (bir olay gönderme) ve sticky event (yeni aboneler için ertelenmiş olay)dır.
Önemli Noktalar
EventBus, Publisher-Subscriber modelini uygulayan Android için bir olay veriyolu kütüphanesidir. Uygulama bileşenleri (Activity, Fragment, Service, ViewModel) arasında açık bağımlılıklar oluşturmadan olayların iletilmesine izin verir. Standart Android mekanizmalarının (Intent, BroadcastReceiver) aksine, EventBus işlem içinde çalışır ve IPC kullanmaz. Kütüphane performans için optimize edilmiştir ve Subscriber Index doğru yapılandırıldığında yansıma kullanmaz.
EventBus mimarisi üç temel unsurdan oluşur: Event (veri içeren POJO sınıfı), Subscriber (@Subscribe ile işaretlenmiş yöntemlere sahip nesne) ve EventBus (merkezi dağıtıcı). Abone, EventBus.getDefault().register(this) aracılığıyla kaydolur ve unregister(this) aracılığıyla kaydı iptal eder. Olaylar türlendirilmiştir: işleyiciler belirli bir olay sınıfına abone olur ve yalnızca bu sınıfın veya alt sınıflarının bir olayı yayınlandığında çağrılır.
// POJO olayı
data class MessageEvent(
val message: String,
val timestamp: Long = System.currentTimeMillis()
)
// Activity'de abone
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
}
}
// Başka bir bileşenden olay gönderme
EventBus.getDefault().post(MessageEvent("Hello from Service"))
Varsayılan olarak, EventBus register() sırasında @Subscribe yöntemlerini bulmak için yansıma kullanır. Subscriber Index, bir ek açıklama işlemcisi aracılığıyla derleme zamanında bir işleyici dizini oluşturur. Bu, yansıma yükünü ortadan kaldırır ve kaydı hızlandırır. Etkinleştirmek için build.gradle'a eventbus-annotation-processor ekleyin. EventBus, classpath'te mevcutsa dizini otomatik olarak kullanır. Dizin olmadan kütüphane yine de çalışır, ancak hafif bir performans düşüşü olur.
EventBus.getDefault().post(event) çağrıldığında, kütüphane olay türünü belirler, bu türü kabul eden @Subscribe yöntemlerine sahip tüm kayıtlı aboneleri bulur ve bunları belirtilen ThreadMode'a göre çağırır. Abone arama, kayıt sırasında oluşturulan Class → CopyOnWriteArrayList
Bir abone onStart() içinde kaydolmalı ve onStop() içinde kaydı iptal etmelidir. onCreate() içinde kaydolup onDestroy() içinde iptal ederseniz, finish() nedeniyle onDestroy'u çağırmadan yok edilen bir Activity abone listesinde kalabilir. Abone sızıntısı, EventBus'ın ana sorunlarından biridir: abone listesinde kalan bir Activity, kaydı iptal edene kadar GC tarafından serbest bırakılmaz. Her zaman register/unregister'ı doğru yaşam döngüsü yöntemlerinde eşleştirin.
@Subscribe ek açıklaması bir priority parametresini (tamsayı, varsayılan 0) destekler. Daha yüksek önceliğe sahip işleyiciler önce çağrılır. cancelEventDelivery(), kalan abonelere olay teslimatını kesmeye izin verir. Bu, alt akış aboneleri tarafından olay işlemeyi iptal edebilen öncelikli işleyiciler (günlükleme, kimlik doğrulama) için kullanışlıdır. Bu işlev yalnızca olay yayınlama iş parçacığında kullanılabilir.
// Öncelikli karmaşık örnek
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)
}
}
// Olay gönderme
EventBus.getDefault().post(NavigationEvent("profile", bundle))
Android, işlem içi iletişim için çeşitli mekanizmalar sunar: EventBus, LocalBroadcastManager (kullanımdan kaldırıldı) ve LiveData/Flow. Her birinin avantajları ve dezavantajları vardır. Seçim, mimari yaklaşıma ve performans gereksinimlerine bağlıdır. Google'ın modern önerileri, Lifecycle entegrasyonu ve sızıntıların olmaması nedeniyle LiveData ve Flow'a yönelmektedir.
| Özellik | EventBus | LocalBroadcastManager | LiveData / Flow |
|---|---|---|---|
| Türleme | Olay sınıfıyla | Intent filtresiyle (String) | Jenerik türle |
| Lifecycle-aware | Hayır (manuel iptal) | Hayır (manuel iptal) | Evet (otomatik) |
| Sticky | Evet (postSticky) | Hayır | Evet (LiveData her zaman sticky) |
| ThreadMode | MAIN, POSTING, BACKGROUND, ASYNC | Sadece main | observe/observeOn ile |
| Performans | Yüksek (Subscriber Index) | Orta (IPC sarmalayıcısı) | Yüksek (gözlem) |
EventBus, önemli miktarda eski kod içeren projelerde ve LiveData/Flow'un mevcut olmadığı (yalnızca Java projeleri) durumlarda kullanışlıdır. EventBus'ın sticky events özelliği, LocalBroadcastManager'da bulunmayan esneklik sağlar. EventBus ayrıca ViewModel olmadan Service'ten Activity'ye olay göndermek için daha kolaydır — özellikle bir arka plan görevinin ilerlemesini bildirmeniz gerektiğinde. Kütüphane minimum boyuta (yaklaşık 50 KB) sahiptir ve bağımlılık eklemez.
LiveData ve Flow, Android Jetpack'in bir parçasıdır ve Lifecycle ile entegredir. Bir bileşen yok edildiğinde otomatik olarak abonelikten çıkarlar ve bellek sızıntılarını ortadan kaldırırlar. Flow, eş yordamları ve karmaşık dönüşüm operatörlerini destekler. Google, UI katmanı için LiveData'yı ve depolar için Flow'u önerir. EventBus, gezinme ve iş mantığının MVVM'ye uymadığı modüller arası olaylar için kullanışlı olmaya devam eder.
Subscribe, @Subscribe ek açıklaması aracılığıyla bir olay işleyicisinin kaydedilmesidir. Yöntem public, void olmalı ve tam olarak bir parametre — olay türü — kabul etmelidir. Post, EventBus.getDefault().post(event) aracılığıyla abone olan tüm işleyicilere bir olay göndermektir. Post yöntemi bir sonuç döndürmez ve kaç işleyicinin çağrıldığını belirtmez. Yanıt gerektiren olaylar için, bir sonuç alanına sahip ayrı bir Event sınıfı kullanın.
Bir olay, herhangi bir Java/Kotlin sınıfıdır. Değişmez olaylar için data class ve değişebilir alanlara sahip olaylar için normal bir sınıf kullanılması önerilir. Olay adlandırması eylemi yansıtmalıdır: UserLoggedInEvent, DataLoadedEvent, NetworkErrorEvent. String türü alanı olan tek bir genel Event sınıfından kaçının — bu, türlemenin avantajlarını ortadan kaldırır. Bir olay hiyerarşisi (üst Event), ilgili olay grubuna abone olmaya izin verir.
// Olay hiyerarşisi
open class UserEvent
data class UserLoggedIn(val userId: String) : UserEvent()
data class UserLoggedOut(val reason: String) : UserEvent()
// Temel sınıfa abone olma
class SessionManager {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onUserEvent(event: UserEvent) {
when (event) {
is UserLoggedIn -> startSession(event.userId)
is UserLoggedOut -> endSession(event.reason)
}
}
}
// Gönderme
EventBus.getDefault().post(UserLoggedIn("user_123"))
EventBus.getDefault().register(this) çağırmak, abone sınıfını yansıma veya Subscriber Index aracılığıyla tarar ve bulunan @Subscribe yöntemlerini olay haritasında saklar. Unregister, aboneyi haritadan kaldırır. Kayıt iptal etmeden yeniden kaydolmak bir hatadır (MultipleSubscriberException fırlatır). Fragment için onStart() içinde kaydolun ve onStop() içinde iptal edin. Service için onCreate() ve onDestroy() içinde. ViewModel için önerilmez — LiveData kullanın.
Sticky event, gönderildikten sonra EventBus'ta kalan bir olaydır. postSticky()'den sonra kaydolan yeni aboneler, ilgili türün son sticky event'ini hemen alır. Bu, başlangıç durumunu iletmek için kullanışlıdır: bir ekran açıldığında, kaydından önce gönderilen en son verileri alır. Bir sticky event'i EventBus.getDefault().removeStickyEvent(Class) aracılığıyla kaldırabilirsiniz.
ThreadMode, işleyicinin hangi iş parçacığında yürütüleceğini belirler. POSTING (varsayılan) — işleyici, post'un çağrıldığı aynı iş parçacığında çalışır. MAIN — işleyici, Handler aracılığıyla ana iş parçacığında çalışır. BACKGROUND — işleyici bir arka plan iş parçacığında çalışır; post ana iş parçacığında çağrıldıysa, EventBus işleyiciyi bir arka plan iş parçacığı kuyruğuna koyar. ASYNC — her işleyici, bir iş parçacığı havuzundan ayrı bir arka plan iş parçacığında çalışır. UI güncellemeleri için MAIN kullanın.
// Sticky Event
data class LocationEvent(val lat: Double, val lng: Double)
// LocationService'ten sticky olay gönderme
EventBus.getDefault().postSticky(LocationEvent(55.7558, 37.6173))
// Abone, kayıttan hemen sonra son konumu alır
class MapFragment : Fragment() {
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
// postSticky çağrıldıysa hemen LocationEvent alır
}
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 olayı kaldırma
EventBus.getDefault().removeStickyEvent(LocationEvent::class.java)
BACKGROUND, tüm işleyiciler için tek bir arka plan iş parçacığı kullanır — sırayla yürütülürler. ASYNC, her işleyici için havuzdan yeni bir iş parçacığı oluşturur — paralel olarak yürütülürler. BACKGROUND, paylaşılan bir veritabanıyla G/Ç işlemleri için uygundur. ASYNC, bağımsız uzun süreli işlemler (ağ istekleri) içindir. Her iki mod da paylaşılan kaynaklara iş parçacığı güvenli erişim gerektirir. İş parçacığı sayısını aklınızda bulundurun: ASYNC havuzu sınırsızdır.
EventBus'ı kullanırken geliştiriciler sıklıkla bellek sızıntılarına, beklenmeyen çağrılara ve performans düşüşüne yol açan hatalar yapar. En kritik olanlar: Activity'de kayıt iptalini unutmak, onCreate'te kaydolmak (onStart/onStop yerine), Object'e (tüm olaylar) abone olmak, sonsuz döngüde olay göndermek. Android Profiler ile profil oluşturma, sorunları belirlemeye yardımcı olur.
En yaygın hata, onDestroy() içinde kaydı iptal etmeden onCreate() içinde bir Activity kaydetmektir. Sonuç: EventBus, Activity'ye bir referans tutar, GC onu serbest bırakamaz. Ekran döndürüldüğünde, önceki Activity bellekte kalırken yeni bir Activity oluşturulur. Çözüm: her zaman onStart/onStop içinde register/unregister'ı eşleştirin. Fragment için aynı modeli kullanın. Bir Activity, finish'ten sonra EventBus tarafından tutuluyorsa, Memory Profiler ile kontrol edin.
Subscriber Index olmadan, EventBus her register()'da @Subscribe yöntemlerini bulmak için yansıma kullanır. Android 6-7 cihazlarında yansıma yavaştır ve 50 ms'ye kadar gecikmelere neden olur. Subscriber Index, yansımayı tamamen ortadan kaldırır: yöntemler, bir ek açıklama işlemcisi aracılığıyla derleme zamanında indekslenir. 20'den fazla abonesi olan projeler için dizin zorunludur. build.gradle'da kapt veya annotationProcessor'ın yapılandırıldığından emin olun.
// build.gradle (app) — Subscriber Index ekleme
dependencies {
implementation 'org.greenrobot:eventbus:3.3.1'
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.3.1'
}
// Kotlin için kapt kullanın
plugins {
id 'kotlin-kapt'
}
dependencies {
implementation 'org.greenrobot:eventbus:3.3.1'
kapt 'org.greenrobot:eventbus-annotation-processor:3.3.1'
}
// Dizin yapılandırması (defaultConfig içinde)
kapt {
arguments {
arg('eventBusIndex', 'com.app.EventBusIndex')
}
}
Kotlin ve Jetpack Compose kullanan modern projeler, kotlinx.coroutines kütüphanesinden SharedFlow ve Channel'ı tercih eder. SharedFlow, tekrar oynatma (sticky), arabelleğe alma ve geri basıncı destekler. Channel, tek seferlik olayları (toast, gezinme) işler. Her iki çözüm de repeatOnLifecycle aracılığıyla Lifecycle ile entegredir ve manuel abonelik iptali gerektirmez. Yeni projeler için EventBus yerine SharedFlow önerilir. Mevcut projeler için yeniden düzenleme sırasında geçiş yapmak haklıdır.
Sıkça Sorulan Sorular
EventBus, herhangi bir bileşen (Activity, Fragment, Service) arasında veri alışverişi için bir olay veriyoludur. LiveData, bir UI bileşeni tarafından gözlemlenen veriler için lifecycle-aware bir sarmalayıcıdır. LiveData, Lifecycle aracılığıyla aboneliği otomatik olarak yönetir. EventBus manuel register/unregister gerektirir. LiveData UI katmanı için, EventBus ise LiveData'nın uygun olmadığı modüller arası iletişim için önerilir.
Sticky event, gönderildikten sonra EventBus'ta kalan bir olaydır. postSticky()'den sonra kaydolan yeni aboneler, son sticky event'i hemen alır. Başlangıç durumu için kullanılır: bir ekran açıldığında, yeni bir istek olmadan en son verileri alır. removeStickyEvent() ile veya aynı türde yeni bir sticky event gönderildiğinde kaldırılır.
Evet, EventBus iş parçacığı güvenlidir. post() herhangi bir iş parçacığından çağrılabilir. Abonelere olay teslimatı dahili olarak senkronize edilir. ThreadMode, işleyici yürütme iş parçacığını belirler: MAIN (Handler aracılığıyla ana iş parçacığı), POSTING (çağıran iş parçacığı), BACKGROUND (arka plan görev kuyruğu), ASYNC (ayrı iş parçacığı). UI güncellemeleri için MAIN, ağır işlemler için ASYNC kullanın.
EventBus.builder().logNoSubscriberMessages(true).sendNoSubscriberEvent(true).install() ile günlük kaydını etkinleştirin. İşleyicisi olmayan olayları izlemek için NoSubscriberEvent'e abone olun. Global istisna işleme için SubscriberExceptionEvent kullanın. Android Profiler sızıntıları bulmaya yardımcı olur. Karmaşık senaryolar için bir test yazın: EventBus.getDefault().register(mock) + post(event) + verify(mock).
Hayır, EventBus (GreenRobot) Android SDK ve JVM'ye bağlıdır. Kotlin Multiplatform için Kotlin Multiplatform SharedFlow veya KMMBus — paylaşılan kodu destekleyen kütüphaneleri kullanın. EventBus, bir KMM projesinin Android tarafında çalışır ancak commonMain'de kullanılamaz. Platformlar arası olaylar için platformun yerel mekanizmalarını veya expect/actual aracılığıyla soyutlamayı tercih edin.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun