EventBus: cos'è, principio di funzionamento e bus di eventi Android

Autore: IT Sectr Pubblicato: 2026-03-18 Tempo di lettura: 10 min

EventBus è una libreria per Android che implementa il pattern Publisher-Subscriber tramite un bus di eventi, consentendo lo scambio di dati tra componenti senza dipendenze dirette. Sviluppata da GreenRobot, la libreria semplifica la comunicazione tra Activity, Fragment, Service e Background Thread. Secondo i dati GitHub (2025), EventBus conta oltre 25 mila stelle ed è utilizzato in migliaia di applicazioni Android. Le operazioni principali sono subscribe (iscrizione a un evento), post (invio di un evento) e sticky event (evento differito per nuovi iscritti).

Punti chiave

  • EventBus è una libreria di bus di eventi per comunicazione debolmente accoppiata in Android.
  • @Subscribe è un'annotazione che contrassegna un metodo come gestore di un tipo di evento specifico.
  • EventBus.getDefault().post() invia un evento a tutti i gestori iscritti.
  • Sticky event conserva l'ultimo evento per la consegna a nuovi iscritti.
  • ThreadMode determina il thread di esecuzione del gestore: MAIN, POSTING, BACKGROUND, ASYNC.

Cos'è EventBus?

EventBus è una libreria di bus di eventi per Android che implementa il pattern Publisher-Subscriber. Consente di passare eventi tra i componenti dell'applicazione (Activity, Fragment, Service, ViewModel) senza creare dipendenze esplicite tra di loro. A differenza dei meccanismi Android standard (Intent, BroadcastReceiver), EventBus funziona all'interno del processo e non utilizza IPC. La libreria è ottimizzata per le prestazioni e non utilizza la riflessione quando Subscriber Index è configurato correttamente.

GreenRobot EventBus: architettura

L'architettura di EventBus è composta da tre elementi chiave: Event (classe POJO con dati), Subscriber (oggetto con metodi annotati con @Subscribe) e EventBus (dispatcher centrale). L'iscritto si registra tramite EventBus.getDefault().register(this) e si deregistra tramite unregister(this). Gli eventi sono tipizzati: i gestori si iscrivono a una classe di evento specifica e vengono invocati solo quando viene pubblicato un evento di quella classe o delle sue sottoclassi.

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

// Iscritto in 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
    }
}

// Invio di evento da un altro componente
EventBus.getDefault().post(MessageEvent("Hello from Service"))

Subscriber Index per le prestazioni

Per impostazione predefinita, EventBus utilizza la riflessione per trovare i metodi @Subscribe durante register(). Subscriber Index genera un indice dei gestori in fase di compilazione tramite un processore di annotazioni. Ciò elimina l'overhead della riflessione e accelera la registrazione. Per abilitarlo, aggiungi eventbus-annotation-processor al build.gradle. EventBus utilizza automaticamente l'indice se disponibile nel classpath. Senza l'indice, la libreria funziona comunque, ma con un leggero calo delle prestazioni.

Come funziona EventBus in Android?

Quando viene chiamato EventBus.getDefault().post(event), la libreria determina il tipo di evento, trova tutti gli iscritti registrati con metodi @Subscribe che accettano quel tipo e li invoca secondo il ThreadMode specificato. La ricerca degli iscritti viene eseguita utilizzando una mappa Class → CopyOnWriteArrayList costruita durante la registrazione. Se un evento non ha iscritti, post viene completato senza errore — questo è un comportamento safe-fail.

Ciclo di vita della registrazione

Un iscritto dovrebbe registrarsi in onStart() e deregistrarsi in onStop(). Se ti registri in onCreate() e ti deregistri in onDestroy(), un'Activity distrutta senza chiamare onDestroy (a causa di finish()) potrebbe rimanere nell'elenco degli iscritti. La perdita di iscritti è uno dei problemi principali di EventBus: un'Activity che rimane nell'elenco degli iscritti non verrà raccolta dal GC finché non si deregistra. Abbina sempre register/unregister nei metodi del ciclo di vita corretti.

Priorità dei gestori

L'annotazione @Subscribe supporta un parametro priority (intero, default 0). I gestori con priorità più alta vengono chiamati per primi. cancelEventDelivery() consente di interrompere la consegna dell'evento agli iscritti rimanenti. Questo è utile per i gestori prioritari (logging, autenticazione) che possono annullare l'elaborazione dell'evento da parte degli iscritti downstream. Questa funzione è disponibile solo nel thread di invio dell'evento.

kotlin
// Esempio complesso con priorità
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)
    }
}

// Invio di evento
EventBus.getDefault().post(NavigationEvent("profile", bundle))

EventBus vs LocalBroadcastManager vs LiveData

Android offre diversi meccanismi per la comunicazione intra-processo: EventBus, LocalBroadcastManager (deprecato) e LiveData/Flow. Ognuno ha i suoi vantaggi e svantaggi. La scelta dipende dall'approccio architetturale e dai requisiti di prestazioni. Le raccomandazioni moderne di Google tendono verso LiveData e Flow grazie all'integrazione con Lifecycle e all'assenza di perdite.

CaratteristicaEventBusLocalBroadcastManagerLiveData / Flow
TipizzazioneTramite classe eventoTramite filtro Intent (String)Tramite tipo generico
Lifecycle-awareNo (deregistrazione manuale)No (deregistrazione manuale)Sì (automatico)
StickySì (postSticky)NoSì (LiveData è sempre sticky)
ThreadModeMAIN, POSTING, BACKGROUND, ASYNCSolo mainTramite observe/observeOn
PrestazioniAlte (Subscriber Index)Medie (wrapper IPC)Alte (osservazione)

Quando EventBus è preferibile

EventBus è utile in progetti con molto codice legacy e dove LiveData/Flow non sono disponibili (progetti solo Java). Gli sticky events di EventBus offrono flessibilità assente in LocalBroadcastManager. EventBus è anche più semplice per inviare eventi da Service ad Activity senza ViewModel — specialmente quando è necessario notificare l'avanzamento di un'attività in background. La libreria ha dimensioni minime (circa 50 KB) e non aggiunge dipendenze.

Quando LiveData/Flow è preferibile

LiveData e Flow fanno parte di Android Jetpack e sono integrati con Lifecycle. Si disiscrivono automaticamente quando un componente viene distrutto, eliminando le perdite di memoria. Flow supporta le coroutine e operatori di trasformazione complessi. Google raccomanda LiveData per il layer UI e Flow per i repository. EventBus rimane utile per eventi tra moduli dove navigazione e logica di business non si adattano a MVVM.

Subscribe e Post: operazioni di base

Subscribe è la registrazione di un gestore di eventi tramite l'annotazione @Subscribe. Il metodo deve essere public, void e accettare esattamente un parametro — il tipo di evento. Post è l'invio di un evento a tutti i gestori iscritti tramite EventBus.getDefault().post(event). Il metodo post non restituisce un risultato né indica quanti gestori sono stati invocati. Per eventi con risposta, utilizza una classe Event separata con un campo risultato.

Creazione di eventi personalizzati

Un evento è qualsiasi classe Java/Kotlin. Si consiglia di utilizzare data class per eventi immutabili e una classe normale per eventi con campi mutabili. La denominazione degli eventi dovrebbe riflettere l'azione: UserLoggedInEvent, DataLoadedEvent, NetworkErrorEvent. Evita una singola classe Event generica con un campo String type — ciò elimina i vantaggi della tipizzazione. Una gerarchia di eventi (Event padre) consente di iscriversi a un gruppo di eventi correlati.

kotlin
// Gerarchia di eventi
open class UserEvent
data class UserLoggedIn(val userId: String) : UserEvent()
data class UserLoggedOut(val reason: String) : UserEvent()

// Iscrizione alla classe base
class SessionManager {
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onUserEvent(event: UserEvent) {
        when (event) {
            is UserLoggedIn -> startSession(event.userId)
            is UserLoggedOut -> endSession(event.reason)
        }
    }
}

// Invio
EventBus.getDefault().post(UserLoggedIn("user_123"))

Registrazione e deregistrazione

Chiamare EventBus.getDefault().register(this) scansiona la classe dell'iscritto tramite riflessione o Subscriber Index e memorizza i metodi @Subscribe trovati nella mappa degli eventi. Unregister rimuove l'iscritto dalla mappa. La ri-registrazione senza deregistrazione è un errore (genererà MultipleSubscriberException). Per Fragment, registrati in onStart() e deregistrati in onStop(). Per Service, in onCreate() e onDestroy(). Per ViewModel, non è raccomandato — utilizza LiveData.

Sticky Events e ThreadMode

Uno sticky event è un evento che persiste in EventBus dopo essere stato inviato. I nuovi iscritti registrati dopo postSticky() ricevono immediatamente l'ultimo sticky event del tipo corrispondente. Questo è comodo per passare lo stato iniziale: all'apertura di uno schermo, riceve i dati più recenti inviati prima della sua registrazione. Puoi rimuovere uno sticky event tramite EventBus.getDefault().removeStickyEvent(Class).

ThreadMode: quattro modalità di esecuzione

ThreadMode determina in quale thread viene eseguito il gestore. POSTING (default) — il gestore viene eseguito nello stesso thread in cui è stato chiamato post. MAIN — il gestore viene eseguito nel thread principale tramite Handler. BACKGROUND — il gestore viene eseguito in un thread in background; se post è stato chiamato nel thread principale, EventBus mette in coda il gestore in un thread in background. ASYNC — ogni gestore viene eseguito in un thread in background separato da un pool di thread. Per gli aggiornamenti UI, usa MAIN.

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

// Invio di sticky event da LocationService
EventBus.getDefault().postSticky(LocationEvent(55.7558, 37.6173))

// L'iscritto riceve l'ultima posizione immediatamente dopo la registrazione
class MapFragment : Fragment() {
    override fun onStart() {
        super.onStart()
        EventBus.getDefault().register(this)
        // Riceverà immediatamente LocationEvent se postSticky è stato chiamato
    }

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

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

// Rimozione di sticky event
EventBus.getDefault().removeStickyEvent(LocationEvent::class.java)

ThreadMode.BACKGROUND vs ASYNC

BACKGROUND utilizza un singolo thread in background per tutti i gestori — vengono eseguiti sequenzialmente. ASYNC crea un nuovo thread dal pool per ogni gestore — vengono eseguiti in parallelo. BACKGROUND è adatto per operazioni di I/O con un database condiviso. ASYNC è per operazioni lunghe indipendenti (richieste di rete). Entrambe le modalità richiedono accesso thread-safe alle risorse condivise. Tieni presente il numero di thread: il pool ASYNC è illimitato.

Errori comuni e prestazioni di EventBus

Quando si utilizza EventBus, gli sviluppatori commettono spesso errori che portano a perdite di memoria, invocazioni inaspettate e degrado delle prestazioni. I più critici: dimenticare la deregistrazione in Activity, registrarsi in onCreate (invece di onStart/onStop), iscriversi a Object (tutti gli eventi), inviare eventi in un ciclo infinito. La profilazione con Android Profiler aiuta a identificare i problemi.

Perdite di memoria tramite EventBus

L'errore più comune è registrare un'Activity in onCreate() senza deregistrarsi in onDestroy(). Risultato: EventBus mantiene un riferimento all'Activity, il GC non può liberarla. Quando si ruota lo schermo, viene creata una nuova Activity mentre quella precedente rimane in memoria. Soluzione: abbina sempre register/unregister in onStart/onStop. Per Fragment, usa lo stesso schema. Se un'Activity viene trattenuta da EventBus dopo finish, verifica con Memory Profiler.

Prestazioni: Subscriber Index

Senza Subscriber Index, EventBus utilizza la riflessione per trovare i metodi @Subscribe a ogni register(). Sui dispositivi Android 6-7, la riflessione è lenta, causando ritardi fino a 50 ms. Subscriber Index elimina completamente la riflessione: i metodi vengono indicizzati in fase di compilazione tramite un processore di annotazioni. Per progetti con 20 o più iscritti, l'indice è obbligatorio. Assicurati che kapt o annotationProcessor sia configurato in build.gradle.

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

// Per Kotlin usa kapt
plugins {
    id 'kotlin-kapt'
}

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

// Configurazione dell'indice (in defaultConfig)
kapt {
    arguments {
        arg('eventBusIndex', 'com.app.EventBusIndex')
    }
}

Alternative a EventBus nell'Android moderno

I progetti moderni che utilizzano Kotlin e Jetpack Compose preferiscono SharedFlow e Channel dalla libreria kotlinx.coroutines. SharedFlow supporta replay (sticky), buffering e backpressure. Channel gestisce eventi monouso (toast, navigazione). Entrambe le soluzioni sono integrate con Lifecycle tramite repeatOnLifecycle e non richiedono disiscrizione manuale. Per i nuovi progetti, SharedFlow è raccomandato al posto di EventBus. Per i progetti esistenti, la migrazione è giustificata durante il refactoring.

Domande frequenti

Qual è la differenza tra EventBus e LiveData?

EventBus è un bus di eventi per lo scambio di dati tra qualsiasi componente (Activity, Fragment, Service). LiveData è un wrapper lifecycle-aware per i dati osservati da un componente UI. LiveData gestisce automaticamente l'iscrizione tramite Lifecycle. EventBus richiede register/unregister manuale. LiveData è raccomandato per il layer UI, EventBus per la comunicazione tra moduli dove LiveData è scomodo.

Cos'è uno sticky event?

Uno sticky event è un evento che persiste in EventBus dopo essere stato inviato. I nuovi iscritti registrati dopo postSticky() ricevono immediatamente l'ultimo sticky event. Viene utilizzato per lo stato iniziale: all'apertura di uno schermo, riceve i dati più recenti senza una nuova richiesta. Viene rimosso tramite removeStickyEvent() o quando viene inviato un nuovo sticky event dello stesso tipo.

EventBus è thread-safe?

, EventBus è thread-safe. È possibile chiamare post() da qualsiasi thread. La consegna degli eventi agli iscritti è sincronizzata internamente. ThreadMode determina il thread di esecuzione del gestore: MAIN (thread principale tramite Handler), POSTING (thread chiamante), BACKGROUND (coda di attività in background), ASYNC (thread separato). Per gli aggiornamenti UI, usa MAIN. Per operazioni pesanti, usa ASYNC.

Come eseguire il debug di EventBus?

Attiva la registrazione tramite EventBus.builder().logNoSubscriberMessages(true).sendNoSubscriberEvent(true).install(). Iscriviti a NoSubscriberEvent per tracciare gli eventi senza gestori. Utilizza SubscriberExceptionEvent per la gestione globale delle eccezioni. Android Profiler aiuta a trovare le perdite. Per scenari complessi, scrivi un test: EventBus.getDefault().register(mock) + post(event) + verify(mock).

EventBus può essere utilizzato in Kotlin Multiplatform?

No, EventBus (GreenRobot) è legato ad Android SDK e JVM. Per Kotlin Multiplatform, utilizza Kotlin Multiplatform SharedFlow o KMMBus — librerie che supportano codice condiviso. EventBus funziona sul lato Android di un progetto KMM ma non è disponibile in commonMain. Per eventi cross-platform, preferisci meccanismi nativi della piattaforma o astrazione tramite expect/actual.

Riepilogo

  • EventBus è una libreria Publisher-Subscriber per Android che implementa un bus di eventi con tipizzazione tramite classi POJO.
  • L'annotazione @Subscribe con parametri threadMode, sticky, priority definisce il comportamento del gestore di eventi.
  • post() invia un evento a tutti gli iscritti in modo sincrono; postSticky() conserva l'evento per nuovi iscritti.
  • ThreadMode controlla il thread di esecuzione: POSTING (thread chiamante), MAIN (UI), BACKGROUND (coda), ASYNC (pool).
  • Subscriber Index tramite processore di annotazioni elimina la riflessione e accelera la registrazione.
  • Le perdite di memoria vengono prevenute abbinando register/unregister in onStart/onStop di Activity o Fragment.
  • Per i nuovi progetti, SharedFlow/Channel di kotlinx.coroutines sono preferibili — sono lifecycle-aware e thread-safe.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche