EventBus: apa itu, prinsip kerja dan bus peristiwa Android

Penulis: IT Sectr Diterbitkan: 2026-03-18 Waktu membaca: 10 mnt

EventBus adalah pustaka untuk Android yang mengimplementasikan pola Publisher-Subscriber melalui bus peristiwa, memungkinkan pertukaran data antar komponen tanpa ketergantungan langsung. Dikembangkan oleh GreenRobot, pustaka ini menyederhanakan komunikasi antara Activity, Fragment, Service dan Background Thread. Menurut data GitHub (2025), EventBus memiliki lebih dari 25 ribu bintang dan digunakan di ribuan aplikasi Android. Operasi utama — subscribe (berlangganan peristiwa), post (mengirim peristiwa) dan sticky event (peristiwa tertunda untuk pelanggan baru).

Poin utama

  • EventBus — pustaka bus peristiwa untuk komunikasi longgar di Android.
  • @Subscribe — anotasi yang menandai metode sebagai penangan peristiwa dari tipe tertentu.
  • EventBus.getDefault().post() mengirim peristiwa ke semua penangan yang berlangganan.
  • Sticky event menyimpan peristiwa terakhir untuk dikirim ke pelanggan baru.
  • ThreadMode menentukan thread eksekusi penangan: MAIN, POSTING, BACKGROUND, ASYNC.

Apa itu EventBus?

EventBus adalah pustaka bus peristiwa untuk Android yang mengimplementasikan pola Publisher-Subscriber (penerbit-pelanggan). Ini memungkinkan pengiriman peristiwa antar komponen aplikasi (Activity, Fragment, Service, ViewModel) tanpa membuat ketergantungan eksplisit di antaranya. Berbeda dengan mekanisme standar Android (Intent, BroadcastReceiver), EventBus bekerja di dalam proses dan tidak menggunakan IPC. Pustaka ini dioptimalkan untuk kinerja dan tidak menggunakan refleksi ketika Subscriber Index dikonfigurasi dengan benar.

GreenRobot EventBus: arsitektur

Arsitektur EventBus terdiri dari tiga elemen kunci: Event (kelas POJO dengan data), Subscriber (objek dengan metode yang ditandai @Subscribe) dan EventBus (dispatcher pusat). Pelanggan mendaftar melalui EventBus.getDefault().register(this), berhenti berlangganan — melalui unregister(this). Peristiwa diketik: penangan berlangganan ke kelas peristiwa tertentu dan hanya dipanggil saat post peristiwa dari kelas ini atau subkelasnya.

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

// Pelanggan di 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
    }
}

// Mengirim peristiwa dari komponen lain
EventBus.getDefault().post(MessageEvent("Hello from Service"))

Subscriber Index untuk kinerja

Secara default, EventBus menggunakan refleksi untuk menemukan metode @Subscribe saat register(). Subscriber Index menghasilkan indeks penangan pada tahap kompilasi melalui pemroses anotasi. Ini menghilangkan overhead refleksi dan mempercepat pendaftaran. Untuk mengaktifkan, tambahkan eventbus-annotation-processor ke build.gradle. EventBus secara otomatis menggunakan indeks jika tersedia di classpath. Tanpa indeks, pustaka masih berfungsi, tetapi dengan penurunan kinerja ringan.

Bagaimana cara kerja EventBus di Android?

Saat memanggil EventBus.getDefault().post(event), pustaka menentukan tipe peristiwa, menemukan semua pelanggan terdaftar dengan metode @Subscribe yang menerima tipe ini, dan memanggilnya sesuai ThreadMode yang ditentukan. Pencarian pelanggan dilakukan melalui peta Class → CopyOnWriteArrayList, yang dibangun saat pendaftaran. Jika peristiwa tidak memiliki pelanggan, post berakhir tanpa kesalahan — ini adalah perilaku safe-fail.

Siklus hidup pendaftaran

Pelanggan harus mendaftar di onStart() dan berhenti berlangganan di onStop(). Jika mendaftar di onCreate() dan berhenti di onDestroy(), Activity yang dihancurkan tanpa memanggil onDestroy (karena finish()) dapat tetap berada di daftar pelanggan. Kebocoran pelanggan — salah satu masalah utama EventBus: Activity yang tersisa di daftar pelanggan tidak akan dikumpulkan oleh GC sampai berhenti berlangganan. Selalu pasangkan register/unregister di metode lifecycle yang benar.

Prioritas penangan

Anotasi @Subscribe mendukung parameter priority (bilangan bulat, default 0). Penangan dengan prioritas lebih tinggi dipanggil lebih awal. cancelEventDelivery() memungkinkan menghentikan pengiriman peristiwa ke pelanggan lainnya. Ini berguna untuk penangan prioritas (logging, otentikasi) yang dapat membatalkan pemrosesan peristiwa oleh pelanggan yang lebih rendah. Fungsi hanya tersedia di thread pengiriman peristiwa.

kotlin
// Contoh kompleks dengan prioritas
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)
    }
}

// Mengirim peristiwa
EventBus.getDefault().post(NavigationEvent("profile", bundle))

EventBus vs LocalBroadcastManager vs LiveData

Android menawarkan beberapa mekanisme untuk komunikasi intra-proses: EventBus, LocalBroadcastManager (usang) dan LiveData/Flow. Masing-masing memiliki kelebihan dan kekurangan. Pilihan tergantung pada pendekatan arsitektur dan persyaratan kinerja. Rekomendasi modern Google cenderung ke LiveData dan Flow karena integrasi dengan Lifecycle dan tidak adanya kebocoran.

KarakteristikEventBusLocalBroadcastManagerLiveData / Flow
PengetikanMelalui kelas peristiwaMelalui Intent filter (String)Melalui tipe generik
Lifecycle-awareTidak (berhenti manual)Tidak (berhenti manual)Ya (otomatis)
StickyYa (postSticky)TidakYa (LiveData — selalu sticky)
ThreadModeMAIN, POSTING, BACKGROUND, ASYNCHanya mainMelalui observe/observeOn
KinerjaTinggi (Subscriber Index)Sedang (pembungkus IPC)Tinggi (observasi)

Kapan EventBus lebih baik

EventBus berguna dalam proyek dengan kode warisan (legacy code) dan di mana LiveData/Flow tidak tersedia (proyek Java-only). Sticky events EventBus memberikan fleksibilitas yang tidak dimiliki LocalBroadcastManager. EventBus juga lebih sederhana untuk mengirim peristiwa dari Service ke Activity tanpa ViewModel — terutama saat perlu memberi tahu tentang kemajuan tugas latar belakang. Pustaka ini memiliki ukuran minimal (sekitar 50 KB) dan tidak menambahkan ketergantungan.

Kapan LiveData/Flow lebih baik

LiveData dan Flow adalah bagian dari Android Jetpack dan terintegrasi dengan Lifecycle. Mereka secara otomatis berhenti berlangganan saat komponen dihancurkan, menghilangkan kebocoran memori. Flow mendukung coroutine dan operator transformasi kompleks. Google merekomendasikan LiveData untuk lapisan UI dan Flow untuk repositori. EventBus tetap untuk peristiwa lintas-modul di mana navigasi dan logika bisnis tidak cocok dengan MVVM.

Subscribe dan Post: operasi dasar

Subscribe — pendaftaran penangan peristiwa melalui anotasi @Subscribe. Metode harus public, void dan menerima tepat satu parameter — tipe peristiwa. Post — mengirim peristiwa ke semua penangan yang berlangganan melalui EventBus.getDefault().post(event). Metode post tidak mengembalikan hasil dan tidak memberi tahu berapa banyak penangan yang dipanggil. Untuk peristiwa dengan jawaban, gunakan kelas Event terpisah dengan bidang untuk hasil.

Membuat peristiwa khusus

Peristiwa — kelas Java/Kotlin apa pun. Disarankan menggunakan data class untuk peristiwa yang tidak dapat diubah dan kelas biasa untuk peristiwa dengan bidang yang dapat diubah. Penamaan peristiwa harus mencerminkan tindakan: UserLoggedInEvent, DataLoadedEvent, NetworkErrorEvent. Hindari satu kelas Event umum dengan bidang String type — ini menghilangkan keuntungan pengetikan. Hierarki peristiwa (Event induk) memungkinkan berlangganan ke sekelompok peristiwa terkait.

kotlin
// Hierarki peristiwa
open class UserEvent
data class UserLoggedIn(val userId: String) : UserEvent()
data class UserLoggedOut(val reason: String) : UserEvent()

// Berlangganan ke kelas dasar
class SessionManager {
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onUserEvent(event: UserEvent) {
        when (event) {
            is UserLoggedIn -> startSession(event.userId)
            is UserLoggedOut -> endSession(event.reason)
        }
    }
}

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

Pendaftaran dan penghentian langganan

Pemanggilan EventBus.getDefault().register(this) memindai kelas pelanggan melalui refleksi atau Subscriber Index dan menyimpan metode @Subscribe yang ditemukan di peta peristiwa. Unregister menghapus pelanggan dari peta. Mendaftar ulang tanpa berhenti berlangganan — kesalahan (MultipleSubscriberException akan terjadi). Untuk Fragment, daftar di onStart() dan berhenti di onStop(). Untuk Service — di onCreate() dan onDestroy(). Untuk ViewModel tidak disarankan — gunakan LiveData.

Sticky Events dan ThreadMode

Sticky event — peristiwa yang disimpan di EventBus setelah dikirim. Pelanggan baru yang mendaftar setelah postSticky() segera menerima sticky-peristiwa terakhir dari tipe yang sesuai. Ini nyaman untuk mengirimkan status awal: saat membuka layar, ia menerima data terakhir yang dikirim sebelum pendaftarannya. Menghapus sticky-peristiwa dapat dilakukan melalui EventBus.getDefault().removeStickyEvent(Class).

ThreadMode: empat mode eksekusi

ThreadMode menentukan di thread mana penangan dipanggil. POSTING (default) — penangan dijalankan di thread yang sama tempat post dipanggil. MAIN — penangan dijalankan di main thread melalui Handler. BACKGROUND — penangan dijalankan di background thread; jika post dipanggil di main thread, EventBus menempatkan penangan di antrian background thread. ASYNC — setiap penangan dijalankan di background thread terpisah dari kumpulan thread. Untuk pembaruan UI, gunakan MAIN.

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

// Mengirim sticky-peristiwa dari LocationService
EventBus.getDefault().postSticky(LocationEvent(55.7558, 37.6173))

// Pelanggan menerima lokasi terakhir segera setelah pendaftaran
class MapFragment : Fragment() {
    override fun onStart() {
        super.onStart()
        EventBus.getDefault().register(this)
        // Segera akan menerima LocationEvent jika ada 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)
    }
}

// Menghapus sticky-peristiwa
EventBus.getDefault().removeStickyEvent(LocationEvent::class.java)

ThreadMode.BACKGROUND vs ASYNC

BACKGROUND menggunakan satu background-thread untuk semua penangan — mereka dijalankan secara berurutan. ASYNC membuat thread baru dari kumpulan untuk setiap penangan — mereka dijalankan secara paralel. BACKGROUND cocok untuk operasi input-output dengan database bersama. ASYNC — untuk operasi panjang independen (permintaan jaringan). Kedua mode memerlukan akses thread-safe ke sumber daya bersama. Jumlah thread: kumpulan ASYNC tidak terbatas.

Kesalahan umum dan kinerja EventBus

Saat menggunakan EventBus, pengembang sering membuat kesalahan yang menyebabkan kebocoran memori, panggilan tak terduga dan penurunan kinerja. Yang paling kritis: lupa berhenti berlangganan di Activity, pendaftaran di onCreate (bukan onStart/onStop), berlangganan ke Object (semua peristiwa), mengirim peristiwa dalam loop tak terbatas. Profiling melalui Android Profiler membantu mengidentifikasi masalah.

Kebocoran memori melalui EventBus

Kesalahan paling umum — pendaftaran Activity di onCreate() tanpa berhenti berlangganan di onDestroy(). Hasil: EventBus menyimpan referensi ke Activity, GC tidak dapat membebaskannya. Saat memutar layar, Activity baru dibuat, yang sebelumnya tetap di memori. Solusi: selalu pasangkan register/unregister di onStart/onStop. Untuk Fragment, gunakan skema yang sama. Jika Activity ditahan oleh EventBus setelah finish, periksa melalui Memory Profiler.

Kinerja: Subscriber Index

Tanpa Subscriber Index, EventBus menggunakan refleksi untuk menemukan metode @Subscribe di setiap register(). Pada perangkat Android 6-7, refleksi bekerja lambat, menyebabkan penundaan hingga 50 ms. Subscriber Index sepenuhnya menghilangkan refleksi: metode diindeks pada tahap kompilasi melalui pemroses anotasi. Untuk proyek dengan 20+ pelanggan, indeks wajib. Periksa apakah kapt atau annotationProcessor terhubung di build.gradle.

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

// Untuk Kotlin gunakan kapt
plugins {
    id 'kotlin-kapt'
}

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

// Konfigurasi indeks (di defaultConfig)
kapt {
    arguments {
        arg('eventBusIndex', 'com.app.EventBusIndex')
    }
}

Alternatif EventBus di Android modern

Proyek modern di Kotlin dan Jetpack Compose lebih memilih SharedFlow dan Channel dari pustaka kotlinx.coroutines. SharedFlow mendukung replay (sticky), buffering dan backpressure. Channel — peristiwa sekali pakai (toast, navigasi). Kedua solusi terintegrasi dengan Lifecycle melalui repeatOnLifecycle dan tidak memerlukan penghentian langganan manual. Untuk proyek baru, SharedFlow direkomendasikan daripada EventBus. Untuk proyek yang ada, migrasi dibenarkan saat refactoring.

Pertanyaan yang sering diajukan

Apa perbedaan antara EventBus dan LiveData?

EventBus adalah bus peristiwa untuk pertukaran data antar komponen mana pun (Activity, Fragment, Service). LiveData adalah pembungkus lifecycle-aware untuk data yang diamati oleh komponen UI. LiveData secara otomatis mengelola langganan melalui Lifecycle. EventBus memerlukan register/unregister manual. LiveData direkomendasikan untuk lapisan UI, EventBus — untuk komunikasi lintas-modul di mana LiveData tidak nyaman.

Apa itu sticky event?

Sticky event — peristiwa yang disimpan di EventBus setelah dikirim. Pelanggan baru yang mendaftar setelah postSticky() segera menerima sticky-peristiwa terakhir. Digunakan untuk status awal: saat membuka layar, ia menerima data terakhir tanpa permintaan berulang. Dihapus melalui removeStickyEvent() atau saat mengirim sticky-peristiwa baru dari tipe yang sama.

Apakah EventBus thread-safe?

Ya, EventBus thread-safe. Panggilan post() dimungkinkan dari thread mana pun. Pengiriman peristiwa ke pelanggan disinkronkan di dalam pustaka. ThreadMode menentukan thread eksekusi penangan: MAIN (main thread melalui Handler), POSTING (thread pengirim), BACKGROUND (antrian tugas latar belakang), ASYNC (thread terpisah). Untuk pembaruan UI gunakan MAIN, untuk operasi berat — ASYNC.

Bagaimana cara men-debug EventBus?

Aktifkan logging melalui EventBus.builder().logNoSubscriberMessages(true).sendNoSubscriberEvent(true).install(). Berlangganan ke NoSubscriberEvent untuk melacak peristiwa tanpa penangan. Gunakan SubscriberExceptionEvent untuk penanganan pengecualian global. Android Profiler membantu menemukan kebocoran. Untuk skenario kompleks, tulis tes: EventBus.getDefault().register(mock) + post(event) + verify(mock).

Bisakah EventBus digunakan di Kotlin Multiplatform?

Tidak, EventBus (GreenRobot) terikat pada Android SDK dan JVM. Untuk Kotlin Multiplatform, gunakan Kotlin Multiplatform SharedFlow atau KMMBus — pustaka yang mendukung kode bersama. EventBus di sisi Android proyek KMM berfungsi, tetapi tidak tersedia di commonMain. Untuk peristiwa lintas-platform, mekanisme asli platform atau abstraksi melalui expect/actual lebih disukai.

Kesimpulan

  • EventBus — pustaka Publisher-Subscriber untuk Android, mengimplementasikan bus peristiwa dengan pengetikan melalui kelas POJO.
  • Anotasi @Subscribe dengan parameter threadMode, sticky, priority menentukan perilaku penangan peristiwa.
  • post() mengirim peristiwa ke semua pelanggan secara sinkron; postSticky() menyimpan peristiwa untuk pelanggan baru.
  • ThreadMode mengelola thread eksekusi: POSTING (thread pengirim), MAIN (UI), BACKGROUND (antrian), ASYNC (kumpulan).
  • Subscriber Index pemroses anotasi menghilangkan refleksi dan mempercepat pendaftaran.
  • Kebocoran memori dicegah dengan memasangkan register/unregister di onStart/onStop Activity atau Fragment.
  • Untuk proyek baru, SharedFlow/Channel dari kotlinx.coroutines lebih baik — mereka lifecycle-aware dan thread-safe.

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga