EventBus: qué es, principio de funcionamiento y bus de eventos en Android

Autor: IT Sectr Publicado: 2026-03-18 Tiempo de lectura: 10 min

EventBus es una biblioteca para Android que implementa el patrón Publisher-Subscriber a través de un bus de eventos, permitiendo intercambiar datos entre componentes sin dependencias directas. Desarrollada por GreenRobot, la biblioteca simplifica la comunicación entre Activity, Fragment, Service y Background Thread. Según datos de GitHub (2025), EventBus cuenta con más de 25 mil estrellas y se utiliza en miles de aplicaciones Android. Las operaciones principales son subscribe (suscripción a un evento), post (envío de un evento) y sticky event (evento diferido para nuevos suscriptores).

Puntos clave

  • EventBus es una biblioteca de bus de eventos para comunicación débilmente acoplada en Android.
  • @Subscribe es una anotación que marca un método como manejador de un tipo de evento específico.
  • EventBus.getDefault().post() envía un evento a todos los manejadores suscritos.
  • Sticky event conserva el último evento para entrega a nuevos suscriptores.
  • ThreadMode determina el hilo de ejecución del manejador: MAIN, POSTING, BACKGROUND, ASYNC.

¿Qué es EventBus?

EventBus es una biblioteca de bus de eventos para Android que implementa el patrón Publisher-Subscriber. Permite pasar eventos entre componentes de la aplicación (Activity, Fragment, Service, ViewModel) sin crear dependencias explícitas entre ellos. A diferencia de los mecanismos estándar de Android (Intent, BroadcastReceiver), EventBus funciona dentro del proceso y no utiliza IPC. La biblioteca está optimizada para el rendimiento y no usa reflexión cuando el Subscriber Index está configurado correctamente.

GreenRobot EventBus: arquitectura

La arquitectura de EventBus consta de tres elementos clave: Event (clase POJO con datos), Subscriber (objeto con métodos anotados con @Subscribe) y EventBus (despachador central). El suscriptor se registra mediante EventBus.getDefault().register(this) y se da de baja mediante unregister(this). Los eventos están tipados: los manejadores se suscriben a una clase de evento específica y solo se invocan cuando se publica un evento de esa clase o sus subclases.

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

// Suscriptor en 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
    }
}

// Envío de evento desde otro componente
EventBus.getDefault().post(MessageEvent("Hello from Service"))

Subscriber Index para rendimiento

Por defecto, EventBus usa reflexión para encontrar métodos @Subscribe durante register(). Subscriber Index genera un índice de manejadores en tiempo de compilación mediante un procesador de anotaciones. Esto elimina la sobrecarga de la reflexión y acelera el registro. Para habilitarlo, agregue eventbus-annotation-processor a build.gradle. EventBus usa el índice automáticamente si está disponible en el classpath. Sin el índice, la biblioteca sigue funcionando pero con una ligera disminución del rendimiento.

¿Cómo funciona EventBus en Android?

Cuando se llama a EventBus.getDefault().post(event), la biblioteca determina el tipo de evento, encuentra todos los suscriptores registrados con métodos @Subscribe que acepten ese tipo y los invoca según el ThreadMode especificado. La búsqueda de suscriptores se realiza mediante un mapa Class → CopyOnWriteArrayList construido durante el registro. Si un evento no tiene suscriptores, post finaliza sin error — esto es un comportamiento safe-fail.

Ciclo de vida del registro

Un suscriptor debe registrarse en onStart() y darse de baja en onStop(). Si se registra en onCreate() y se da de baja en onDestroy(), una Activity destruida sin llamar a onDestroy (debido a finish()) puede permanecer en la lista de suscriptores. La fuga de suscriptores es uno de los principales problemas de EventBus: una Activity que permanece en la lista de suscriptores no será recolectada por el GC hasta que se dé de baja. Siempre empareje register/unregister en los métodos de ciclo de vida correctos.

Prioridad de manejadores

La anotación @Subscribe admite un parámetro priority (entero, por defecto 0). Los manejadores con mayor prioridad se invocan primero. cancelEventDelivery() permite interrumpir la entrega del evento a los suscriptores restantes. Esto es útil para manejadores prioritarios (logging, autenticación) que pueden cancelar el procesamiento del evento por suscriptores downstream. Esta función solo está disponible en el hilo de envío del evento.

kotlin
// Ejemplo complejo con prioridad
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)
    }
}

// Envío de evento
EventBus.getDefault().post(NavigationEvent("profile", bundle))

EventBus vs LocalBroadcastManager vs LiveData

Android ofrece varios mecanismos para la comunicación dentro del proceso: EventBus, LocalBroadcastManager (obsoleto) y LiveData/Flow. Cada uno tiene sus ventajas y desventajas. La elección depende del enfoque arquitectónico y los requisitos de rendimiento. Las recomendaciones modernas de Google se inclinan hacia LiveData y Flow debido a la integración con Lifecycle y la ausencia de fugas.

CaracterísticaEventBusLocalBroadcastManagerLiveData / Flow
TipadoMediante clase de eventoMediante filtro Intent (String)Mediante tipo genérico
Lifecycle-awareNo (baja manual)No (baja manual)Sí (automático)
StickySí (postSticky)NoSí (LiveData siempre es sticky)
ThreadModeMAIN, POSTING, BACKGROUND, ASYNCSolo mainMediante observe/observeOn
RendimientoAlto (Subscriber Index)Medio (envoltorio IPC)Alto (observación)

Cuándo es preferible EventBus

EventBus es útil en proyectos con código heredado significativo y donde LiveData/Flow no están disponibles (proyectos solo Java). Los sticky events de EventBus brindan una flexibilidad ausente en LocalBroadcastManager. EventBus también es más fácil para enviar eventos desde Service a Activity sin ViewModel, especialmente cuando se necesita notificar el progreso de una tarea en segundo plano. La biblioteca tiene un tamaño mínimo (alrededor de 50 KB) y no agrega dependencias.

Cuándo es preferible LiveData/Flow

LiveData y Flow son parte de Android Jetpack y están integrados con Lifecycle. Se dan de baja automáticamente cuando un componente se destruye, eliminando las fugas de memoria. Flow admite corrutinas y operadores de transformación complejos. Google recomienda LiveData para la capa de UI y Flow para repositorios. EventBus sigue siendo útil para eventos entre módulos donde la navegación y la lógica de negocio no encajan en MVVM.

Subscribe y Post: operaciones básicas

Subscribe es el registro de un manejador de eventos mediante la anotación @Subscribe. El método debe ser public, void y aceptar exactamente un parámetro — el tipo de evento. Post es el envío de un evento a todos los manejadores suscritos mediante EventBus.getDefault().post(event). El método post no devuelve un resultado ni indica cuántos manejadores fueron invocados. Para eventos con respuesta, use una clase Event separada con un campo de resultado.

Creación de eventos personalizados

Un evento es cualquier clase de Java/Kotlin. Se recomienda usar data class para eventos inmutables y una clase normal para eventos con campos mutables. El nombre del evento debe reflejar la acción: UserLoggedInEvent, DataLoadedEvent, NetworkErrorEvent. Evite una clase Event genérica única con un campo String type — esto elimina los beneficios del tipado. Una jerarquía de eventos (Event padre) permite suscribirse a un grupo de eventos relacionados.

kotlin
// Jerarquía de eventos
open class UserEvent
data class UserLoggedIn(val userId: String) : UserEvent()
data class UserLoggedOut(val reason: String) : UserEvent()

// Suscripción a la clase base
class SessionManager {
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onUserEvent(event: UserEvent) {
        when (event) {
            is UserLoggedIn -> startSession(event.userId)
            is UserLoggedOut -> endSession(event.reason)
        }
    }
}

// Envío
EventBus.getDefault().post(UserLoggedIn("user_123"))

Registro y cancelación de registro

Llamar a EventBus.getDefault().register(this) escanea la clase del suscriptor mediante reflexión o Subscriber Index y almacena los métodos @Subscribe encontrados en el mapa de eventos. Unregister elimina al suscriptor del mapa. Volver a registrarse sin cancelar el registro es un error (lanzará MultipleSubscriberException). Para Fragment, regístrese en onStart() y cancele en onStop(). Para Service, en onCreate() y onDestroy(). Para ViewModel, no se recomienda — use LiveData.

Sticky Events y ThreadMode

Un sticky event es un evento que persiste en EventBus después de ser enviado. Los nuevos suscriptores registrados después de postSticky() reciben inmediatamente el último sticky event del tipo correspondiente. Esto es conveniente para pasar el estado inicial: al abrir una pantalla, recibe los últimos datos enviados antes de su registro. Puede eliminar un sticky event mediante EventBus.getDefault().removeStickyEvent(Class).

ThreadMode: cuatro modos de ejecución

ThreadMode determina en qué hilo se ejecuta el manejador. POSTING (predeterminado) — el manejador se ejecuta en el mismo hilo donde se llamó a post. MAIN — el manejador se ejecuta en el hilo principal mediante Handler. BACKGROUND — el manejador se ejecuta en un hilo secundario; si post se llamó en el hilo principal, EventBus pone en cola el manejador en un hilo secundario. ASYNC — cada manejador se ejecuta en un hilo secundario separado de un grupo de hilos. Para actualizaciones de UI, use MAIN.

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

// Envío de sticky event desde LocationService
EventBus.getDefault().postSticky(LocationEvent(55.7558, 37.6173))

// El suscriptor recibe la última ubicación inmediatamente después del registro
class MapFragment : Fragment() {
    override fun onStart() {
        super.onStart()
        EventBus.getDefault().register(this)
        // Recibirá inmediatamente LocationEvent si se llamó a 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)
    }
}

// Eliminación de sticky event
EventBus.getDefault().removeStickyEvent(LocationEvent::class.java)

ThreadMode.BACKGROUND vs ASYNC

BACKGROUND usa un solo hilo en segundo plano para todos los manejadores — se ejecutan secuencialmente. ASYNC crea un nuevo hilo del grupo para cada manejador — se ejecutan en paralelo. BACKGROUND es adecuado para operaciones de E/S con una base de datos compartida. ASYNC es para operaciones largas independientes (solicitudes de red). Ambos modos requieren acceso thread-safe a recursos compartidos. Tenga en cuenta el número de hilos: el grupo ASYNC es ilimitado.

Errores comunes y rendimiento de EventBus

Al usar EventBus, los desarrolladores suelen cometer errores que provocan fugas de memoria, invocaciones inesperadas y degradación del rendimiento. Los más críticos: olvidar la cancelación del registro en Activity, registrarse en onCreate (en lugar de onStart/onStop), suscribirse a Object (todos los eventos), enviar eventos en un bucle infinito. La creación de perfiles con Android Profiler ayuda a identificar problemas.

Fugas de memoria mediante EventBus

El error más común es registrar una Activity en onCreate() sin cancelar el registro en onDestroy(). Resultado: EventBus mantiene una referencia a la Activity, el GC no puede liberarla. Al rotar la pantalla, se crea una nueva Activity mientras la anterior permanece en memoria. Solución: siempre empareje register/unregister en onStart/onStop. Para Fragment, use el mismo patrón. Si una Activity es retenida por EventBus después de finish, verifique con Memory Profiler.

Rendimiento: Subscriber Index

Sin Subscriber Index, EventBus usa reflexión para encontrar métodos @Subscribe en cada register(). En dispositivos con Android 6-7, la reflexión es lenta, causando demoras de hasta 50 ms. Subscriber Index elimina la reflexión por completo: los métodos se indexan en tiempo de compilación mediante un procesador de anotaciones. Para proyectos con 20 o más suscriptores, el índice es obligatorio. Asegúrese de que kapt o annotationProcessor esté configurado en build.gradle.

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

// Para Kotlin use kapt
plugins {
    id 'kotlin-kapt'
}

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

// Configuración del índice (en defaultConfig)
kapt {
    arguments {
        arg('eventBusIndex', 'com.app.EventBusIndex')
    }
}

Alternativas a EventBus en Android moderno

Los proyectos modernos que usan Kotlin y Jetpack Compose prefieren SharedFlow y Channel de la biblioteca kotlinx.coroutines. SharedFlow admite replay (sticky), buffering y backpressure. Channel maneja eventos de una sola vez (toast, navegación). Ambas soluciones están integradas con Lifecycle mediante repeatOnLifecycle y no requieren cancelación manual de suscripción. Para proyectos nuevos, se recomienda SharedFlow en lugar de EventBus. Para proyectos existentes, la migración está justificada durante la refactorización.

Preguntas frecuentes

¿Cuál es la diferencia entre EventBus y LiveData?

EventBus es un bus de eventos para el intercambio de datos entre cualquier componente (Activity, Fragment, Service). LiveData es un envoltorio lifecycle-aware para datos observados por un componente de UI. LiveData gestiona automáticamente la suscripción a través de Lifecycle. EventBus requiere register/unregister manual. LiveData se recomienda para la capa de UI, EventBus para la comunicación entre módulos donde LiveData es incómodo.

¿Qué es un sticky event?

Un sticky event es un evento que persiste en EventBus después de ser enviado. Los nuevos suscriptores registrados después de postSticky() reciben inmediatamente el último sticky event. Se usa para el estado inicial: al abrir una pantalla, recibe los últimos datos sin una nueva solicitud. Se elimina mediante removeStickyEvent() o cuando se envía un nuevo sticky event del mismo tipo.

¿Es EventBus thread-safe?

, EventBus es thread-safe. Se puede llamar a post() desde cualquier hilo. La entrega de eventos a los suscriptores se sincroniza internamente. ThreadMode determina el hilo de ejecución del manejador: MAIN (hilo principal mediante Handler), POSTING (hilo de la llamada), BACKGROUND (cola de tareas en segundo plano), ASYNC (hilo separado). Para actualizaciones de UI, use MAIN. Para operaciones pesadas, use ASYNC.

¿Cómo depurar EventBus?

Habilite el registro mediante EventBus.builder().logNoSubscriberMessages(true).sendNoSubscriberEvent(true).install(). Suscríbase a NoSubscriberEvent para rastrear eventos sin manejadores. Use SubscriberExceptionEvent para el manejo global de excepciones. Android Profiler ayuda a encontrar fugas. Para escenarios complejos, escriba una prueba: EventBus.getDefault().register(mock) + post(event) + verify(mock).

¿Se puede usar EventBus en Kotlin Multiplatform?

No, EventBus (GreenRobot) está vinculado a Android SDK y JVM. Para Kotlin Multiplatform, use Kotlin Multiplatform SharedFlow o KMMBus — bibliotecas que admiten código compartido. EventBus funciona en el lado Android de un proyecto KMM pero no está disponible en commonMain. Para eventos multiplataforma, prefiera mecanismos nativos de la plataforma o una abstracción mediante expect/actual.

Resumen

  • EventBus es una biblioteca Publisher-Subscriber para Android que implementa un bus de eventos con tipado mediante clases POJO.
  • La anotación @Subscribe con parámetros threadMode, sticky, priority define el comportamiento del manejador de eventos.
  • post() envía un evento a todos los suscriptores de forma síncrona; postSticky() conserva el evento para nuevos suscriptores.
  • ThreadMode controla el hilo de ejecución: POSTING (hilo de la llamada), MAIN (UI), BACKGROUND (cola), ASYNC (grupo).
  • Subscriber Index mediante procesador de anotaciones elimina la reflexión y acelera el registro.
  • Las fugas de memoria se previenen con register/unregister emparejados en onStart/onStop de Activity o Fragment.
  • Para proyectos nuevos, SharedFlow/Channel de kotlinx.coroutines son preferibles — son lifecycle-aware y thread-safe.

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también