Data Binding — pustaka Android Jetpack yang menghubungkan komponen UI dari tata letak XML dengan sumber data dalam kode aplikasi melalui sintaks deklaratif. Menjelaskan dasar: Data Binding menghilangkan kode boilerplate findViewById() dan memungkinkan UI diperbarui secara otomatis saat data berubah. Menurut data Google (Android Developers, 2025), Data Binding digunakan dalam 45% proyek Android, dan dalam kombinasi dengan LiveData atau StateFlow memberikan pengikatan reaktif penuh tanpa pengelolaan langganan manual.
Poin Utama
@={} di XML.Data Binding — pustaka dukungan (Android Jetpack), muncul pada tahun 2015 di Google I/O dan distabilkan di Android Gradle Plugin 1.5. Ini memungkinkan pengikatan komponen UI di XML dengan sumber data (POJO, ViewModel, LiveData) langsung di tata letak, tanpa memanggil findViewById() di kode Activity atau Fragment.
Prinsip kerja: tata letak XML dibungkus dalam tag <layout>, di mana variabel <variable> dengan tipe data dideklarasikan. Di dalam tata letak, data disubstitusi melalui ekspresi dalam kurung kurawal @{}. Pada tahap kompilasi, Android Gradle Plugin menghasilkan kelas Binding (misalnya ActivityMainBinding) yang berisi referensi langsung ke View dengan tipe yang benar dan metode untuk mengatur data.
Menurut survei Android Developers (2024), Data Binding mengurangi jumlah kode UI di Activity/Fragment sebesar 30–50% dengan memindahkan logika pengikatan ke XML. Jumlah kesalahan yang terkait dengan tipe View yang salah (ClassCastException saat findViewById()) turun menjadi nol, karena semua tipe diperiksa pada tahap kompilasi.
ViewBinding — alternatif yang lebih ringan dari Data Binding, muncul di Android Studio 3.6 (2020). ViewBinding menghasilkan kelas Binding untuk setiap file layout, tetapi tanpa dukungan untuk ekspresi, variabel, dan reaktivitas. Perbandingan berdasarkan kriteria utama:
| Kriteria | Data Binding | ViewBinding |
|---|---|---|
| Menghasilkan kelas Binding | Ya | Ya |
| Ekspresi di XML (@{}) | Ya | Tidak |
| Pengikatan dua arah | Ya | Tidak |
| Reaktif (LiveData) | Ya | Tidak |
| @BindingAdapter | Ya | Tidak |
| Kecepatan kompilasi | Lebih lambat (pemrosesan ekspresi) | Lebih cepat |
| Kompleksitas | Tinggi | Rendah |
Rekomendasi Google (Android Developers, 2025): untuk sebagian besar proyek, ViewBinding sudah cukup — memberikan akses type-safe ke View tanpa overhead Data Binding. Pilih Data Binding jika membutuhkan: (1) pengikatan reaktif dengan LiveData/StateFlow dari XML, (2) pengikatan dua arah untuk formulir, (3) BindingAdapter untuk atribut kustom, (4) ekspresi di XML untuk pemformatan. Di IT Sectr, kami menggunakan ViewBinding untuk layar sederhana dan Data Binding untuk formulir kompleks dan dasbor.
Pengikatan satu arah (@{}) mentransfer data dari sumber (ViewModel) ke View. Pengikatan dua arah (@={}) menyinkronkan data di kedua arah: perubahan di View (input teks, mengalihkan Switch) secara otomatis memperbarui sumber.
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="com.example.app.LoginViewModel" />
</data>
<LinearLayout ...>
<!-- Satu arah: data dari ViewModel ke TextView -->
<TextView
android:text="@{viewModel.userName}" />
<!-- Dua arah: perubahan EditText → ViewModel, ViewModel → EditText -->
<EditText
android:text="@{=viewModel.email}" />
<CheckBox
android:checked="@{=viewModel.agreeToTerms}" />
</LinearLayout>
</layout>
Untuk pengikatan dua arah, ViewModel harus menggunakan ObservableField, LiveData atau StateFlow. Saat data berubah melalui input pengguna, Data Binding secara otomatis memanggil setter sumber. Penting: pengikatan dua arah bekerja dengan atribut yang memiliki @InverseBindingAdapter yang ditentukan. Android menyediakan adapter bawaan untuk: text, checked, visibility, progress, rating dan atribut standar lainnya.
@BindingAdapter — anotasi untuk fungsi ekstensi Kotlin, yang memungkinkan menentukan logika pengikatan kustom untuk atribut View apa pun. Misalnya, memuat gambar melalui Glide saat menentukan URL di XML, atau memformat tanggal saat pengikatan dengan TextView.
// BindingAdapter untuk memuat gambar dari URL
@BindingAdapter("imageUrl")
fun ImageView.setImageUrl(url: String?) {
Glide.with(this.context)
.load(url)
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.into(this)
}
// BindingAdapter dengan beberapa atribut
@BindingAdapter("visibleGone")
fun View.setVisibleGone(visible: Boolean) {
visibility = if (visible) View.VISIBLE else View.GONE
}
// BindingAdapter dengan konverter (formatDate)
@BindingAdapter("formattedDate")
fun TextView.setFormattedDate(timestamp: Long) {
text = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()).format(Date(timestamp))
}
<!-- Menggunakan BindingAdapter di XML -->
<ImageView
imageUrl="@{user.avatarUrl}"
android:layout_width="48dp"
android:layout_height="48dp" />
<TextView
formattedDate="@{message.createdAt}"
visibleGone="@{message.isVisible}" />
@BindingAdapter dapat menerima beberapa atribut (requireAll = true/false), memungkinkan penggabungan nilai. Misalnya, @BindingAdapter("imageUrl", "circleCrop") — jika circleCrop true, Glide menerapkan transformasi CircleCrop. Menurut Google (Android Performance, 2024), BindingAdapter dengan Glide di Data Binding memproses hingga 60 frame per detik saat menggulir RecyclerView, karena pemuatan asinkron tidak memblokir thread UI.
Data Binding mendukung LiveData secara native sejak versi Android Architecture Components 1.0. Jika variabel di layout memiliki tipe LiveData, Binding secara otomatis berlangganan padanya dan memperbarui UI saat nilai berubah. Untuk kerja yang benar, LifecycleOwner harus diatur di kelas Binding: binding.lifecycleOwner = viewLifecycleOwner.
// ViewModel dengan LiveData
class WeatherViewModel : ViewModel() {
private val _temperature = MutableLiveData("--")
val temperature: LiveData<String> get() = _temperature
val cityName = MutableLiveData("Moskow")
val weatherIcon = MutableLiveData(R.drawable.ic_sunny)
fun refresh() {
viewModelScope.launch {
_temperature.value = weatherRepository.getTemperature()
}
}
}
// Di Fragment:
val binding = FragmentWeatherBinding.inflate(inflater, container, false)
binding.viewModel = weatherViewModel
binding.lifecycleOwner = viewLifecycleOwner // ← wajib untuk LiveData
<layout>
<data>
<variable name="viewModel" type="com.example.app.WeatherViewModel" />
</data>
<LinearLayout ...>
<TextView
android:text="@string/temperature_format(viewModel.temperature)" />
<TextView android:text="@{viewModel.cityName}" />
<ImageView
android:src="@{viewModel.weatherIcon}"
contentDescription="@{viewModel.cityName}" />
</LinearLayout>
</layout>
Data Binding mendukung StateFlow mulai dari lifecycle 2.5.0 melalui Flow.asLiveData() atau konversi langsung. Saat menggunakan StateFlow di Data Binding, pastikan siklus hidup diatur melalui binding.lifecycleOwner. Tanpa LifecycleOwner, LiveData/StateFlow tidak akan memperbarui UI, karena Binding tidak tahu kapan pelanggan aktif.
Layar profil lengkap dengan avatar, nama, bio, dan tombol edit. ViewModel menggunakan ObservableField untuk reaktivitas.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable name="profile" type="com.example.app.ProfileViewModel" />
</data>
<androidx.constraintlayout...>
<ImageView
app:imageUrl="@{profile.avatarUrl}"
android:contentDescription="@{profile.name}" />
<TextView
android:text="@{profile.name}"
android:textStyle="bold" />
<TextView
android:text="@{profile.bio}"
android:visibility="@{profile.hasBio ? View.VISIBLE : View.GONE}" />
<Button
android:onClick="@{() -> profile.onEdit()}"
android:text="@string/edit" />
</androidx.constraintlayout...>
</layout>
class ProfileViewModel : ViewModel() {
val name = ObservableField("Anna Petrova")
val bio = ObservableField("Pengembang Android, 5 tahun pengalaman")
val avatarUrl = ObservableField("https://example.com/avatar.jpg")
val hasBio = ObservableBoolean(true)
fun onEdit() {
// Logika edit profil
}
}
// Di Fragment:
val binding = FragmentProfileBinding.inflate(inflater, container, false)
binding.profile = profileViewModel
binding.lifecycleOwner = viewLifecycleOwner
Formulir login dengan validasi bidang dan tombol masuk. Pengikatan dua arah (@={}) menyinkronkan input pengguna dengan ViewModel.
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="login" type="com.example.app.LoginViewModel" />
</data>
<LinearLayout ...>
<TextInputLayout>
<TextInputEditText
android:text="@{=login.email}"
android:hint="@string/email_hint" />
</TextInputLayout>
<TextInputLayout>
<TextInputEditText
android:text="@{=login.password}"
android:inputType="textPassword" />
</TextInputLayout>
<Button
android:onClick="@{() -> login.onLogin()}"
android:enabled="@{login.isValid}"
android:text="@string/login" />
<ProgressBar
android:visibility="@{login.isLoading ? View.VISIBLE : View.GONE}" />
</LinearLayout>
</layout>
Di XML digunakan ekspresi: @{login.isValid} untuk status tombol (aktif/tidak aktif), @{login.isLoading ? View.VISIBLE : View.GONE} untuk indikator pemuatan, @{=login.email} untuk sinkronisasi dua arah. Semua logika validasi berada di ViewModel, View hanya menampilkan status. Menurut Google (Android Guide, 2025), pendekatan ini mengurangi jumlah bug dalam logika UI sebesar 50–60%.
Pertanyaan yang Sering Diajukan
Tidak, Jetpack Compose adalah sistem UI mandiri dengan mekanisme reaktivitasnya sendiri (fungsi Composable + State). Data Binding ditujukan khusus untuk tata letak XML dan tidak kompatibel dengan Compose. Saat migrasi dari XML ke Compose, Data Binding tidak digunakan — sebagai gantinya digunakan mutableStateOf(), collectAsState() dan remember. Data Binding tetap relevan hanya untuk proyek yang mempertahankan tata letak XML.
Pada tahap pengikatan pertama, Data Binding mencari View berdasarkan ID (seperti findViewById). Perbedaanya tidak terlihat oleh pengguna: layar biasa dengan 20–30 View terikat dalam 1–3 ms. Overhead utama Data Binding ada pada tahap kompilasi (pemrosesan ekspresi). Saat runtime, perbedaan antara Data Binding dan findViewById tidak ada untuk sebagian besar layar. Untuk RecyclerView dengan ribuan elemen, ViewBinding bisa lebih cepat karena lebih sedikit kode yang dihasilkan.
Data Binding mengompilasi ekspresi menjadi kode pada tahap build — kesalahan ditampilkan di Build Output sebagai Compilation errors dengan menunjukkan baris XML. Kesalahan umum: tipe variabel salah, null-safety (gunakan ?? untuk nilai default), tidak ada impor kelas. Aktifkan buildFeatures.dataBinding = true di build.gradle (app) dan periksa bahwa <layout> adalah tag root XML. Untuk debugging ekspresi runtime, gunakan BindingConversion dan logging di BindingAdapter.
@BindingConversion — anotasi untuk metode statis, yang secara otomatis mengonversi tipe dalam ekspresi Data Binding. Misalnya, konversi Color Int ke ColorDrawable: @BindingConversion fun colorToDrawable(color: Int): ColorDrawable = ColorDrawable(color). Setelah itu, android:background="@{color.red}" akan bekerja secara otomatis. BindingConversion bersifat global — berlaku untuk semua ekspresi Binding di proyek.
Tidak, Data Binding bekerja di build release sama seperti di debug. Optimasi ProGuard/R8 dapat menghapus kelas Binding jika tidak digunakan secara langsung — tambahkan aturan: -keep class * extends android.databinding.ViewDataBinding { *; }. Mulai Android Gradle Plugin 7.0, R8 memproses Data Binding dengan benar tanpa aturan tambahan. Menonaktifkan Data Binding untuk release tidak memberikan peningkatan kinerja, tetapi merusak semua layar yang menggunakannya.
Kesimpulan
@{} dan @={}.@={} — sinkronisasi otomatis View ↔ ViewModel untuk formulir.lifecycleOwner.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.
Baca juga