Data Binding — bildirimsel sözdizimi aracılığıyla XML düzenlerindeki UI bileşenlerini uygulama kodundaki veri kaynaklarına bağlayan bir Android Jetpack kütüphanesidir. Temelleri açıklıyoruz: Data Binding, findViewById() tekrar kodunu ortadan kaldırır ve veri değiştiğinde UI'yı otomatik olarak günceller. Google'a göre (Android Developers, 2025), Data Binding Android projelerinin %45inde kullanılır ve LiveData veya StateFlow ile kombinasyon halinde manuel abonelik yönetimi olmadan tamamen reaktif bağlama sağlar.
Önemli Noktalar
@={} ile View ve ViewModel arasında otomatik veri senkronizasyonu.Data Binding, ilk olarak 2015'te Google I/O'da ortaya çıkan ve Android Gradle Plugin 1.5'te kararlı hale getirilen bir destek kütüphanesidir (Android Jetpack). Activity veya Fragment kodunda findViewById() çağırmadan XML'deki UI bileşenlerini doğrudan düzen içinde veri kaynaklarına (POJO, ViewModel, LiveData) bağlamaya olanak tanır.
Çalışma prensibi: XML düzeni, bir veri türüyle <variable> bildiren <layout> etiketine sarılır. Düzen içinde veriler, süslü parantezler @{} içindeki ifadelerle değiştirilir. Derleme zamanında Android Gradle Plugin, doğru türlerle View'lara doğrudan referanslar ve veri ayarlama yöntemleri içeren bir Binding sınıfı (örneğin ActivityMainBinding) oluşturur.
Android Developers Anketine (2024) göre Data Binding, bağlama mantığını XML'e taşıyarak Activity/Fragment'teki UI kodu miktarını %30–50 oranında azaltır. findViewById() ile ClassCastException gibi yanlış View türüyle ilgili hataların sayısı, tüm türler derleme zamanında kontrol edildiği için sıfıra düşer.
ViewBinding, Android Studio 3.6'da (2020) tanıtılan Data Binding'in daha hafif bir alternatifidir. ViewBinding her düzen dosyası için bir Binding sınıfı oluşturur ancak ifadeler, değişkenler ve reaktivite desteği olmadan. Anahtar kriterlere göre karşılaştırma:
| Kriter | Data Binding | ViewBinding |
|---|---|---|
| Binding sınıfı oluşturma | Evet | Evet |
| XML ifadeleri (@{}) | Evet | Hayır |
| Çift yönlü bağlama | Evet | Hayır |
| Reaktif (LiveData) | Evet | Hayır |
| @BindingAdapter | Evet | Hayır |
| Derleme hızı | Daha yavaş (ifade işleme) | Daha hızlı |
| Karmaşıklık | Yüksek | Düşük |
Google'ın önerisi (Android Developers, 2025): çoğu proje için ViewBinding yeterlidir — Data Binding'in ek yükü olmadan View'lara type-safe erişim sağlar. Data Binding'i şu durumlarda seçin: (1) XML'den LiveData/StateFlow ile reaktif bağlama, (2) formlar için çift yönlü bağlama, (3) özel öznitelikler için BindingAdapter, (4) biçimlendirme için XML ifadeleri. IT Sectr'de basit ekranlar için ViewBinding, karmaşık formlar ve panolar için Data Binding kullanıyoruz.
Tek yönlü bağlama (@{}) verileri kaynaktan (ViewModel) View'e iletir. Çift yönlü bağlama (@={}) verileri her iki yönde senkronize eder: View'deki değişiklikler (metin girişi, Switch değiştirme) kaynağı otomatik olarak günceller.
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="com.example.app.LoginViewModel" />
</data>
<LinearLayout ...>
<!-- Tek yönlü: ViewModel'den TextView'e veri -->
<TextView
android:text="@{viewModel.userName}" />
<!-- Çift yönlü: EditText değişiklikleri → ViewModel, ViewModel → EditText -->
<EditText
android:text="@{=viewModel.email}" />
<CheckBox
android:checked="@{=viewModel.agreeToTerms}" />
</LinearLayout>
</layout>
Çift yönlü bağlama için ViewModel'in ObservableField, LiveData veya StateFlow kullanması gerekir. Kullanıcı girişiyle veri değiştiğinde Data Binding otomatik olarak kaynağın setter'ını çağırır. Önemli: çift yönlü bağlama, @InverseBindingAdapter tanımlanmış özniteliklerle çalışır. Android şunlar için yerleşik bağdaştırıcılar sağlar: text, checked, visibility, progress, rating ve diğer standart öznitelikler.
@BindingAdapter, herhangi bir View özniteliği için özel bağlama mantığı tanımlamaya olanak tanıyan Kotlin uzantı işlevleri için bir ek açıklamadır. Örneğin, XML'de bir URL belirtirken Glide aracılığıyla resim yüklemek veya bir TextView'a bağlanırken tarih biçimlendirmek.
// URL ile resim yüklemek için BindingAdapter
@BindingAdapter("imageUrl")
fun ImageView.setImageUrl(url: String?) {
Glide.with(this.context)
.load(url)
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.into(this)
}
// Birden çok özniteliğe sahip BindingAdapter
@BindingAdapter("visibleGone")
fun View.setVisibleGone(visible: Boolean) {
visibility = if (visible) View.VISIBLE else View.GONE
}
// Dönüştürücü ile BindingAdapter (formatDate)
@BindingAdapter("formattedDate")
fun TextView.setFormattedDate(timestamp: Long) {
text = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()).format(Date(timestamp))
}
<!-- XML'de BindingAdapter kullanımı -->
<ImageView
imageUrl="@{user.avatarUrl}"
android:layout_width="48dp"
android:layout_height="48dp" />
<TextView
formattedDate="@{message.createdAt}"
visibleGone="@{message.isVisible}" />
@BindingAdapter birden çok özniteliği (requireAll = true/false) kabul ederek değerlerin birleştirilmesine olanak tanır. Örneğin, @BindingAdapter("imageUrl", "circleCrop") — circleCrop true ise Glide CircleCrop dönüşümünü uygular. Google'a göre (Android Performance, 2024), Data Binding'de Glide ile BindingAdapter, RecyclerView kaydırılırken saniyede 60 kareye kadar işlem yapar çünkü asenkron yükleme UI iş parçacığını engellemez.
Data Binding, Android Architecture Components 1.0'dan beri LiveData'yı yerel olarak destekler. Düzendeki bir değişken LiveData türündeyse Binding otomatik olarak ona abone olur ve değer değiştiğinde UI'yı günceller. Doğru çalışma için Binding sınıfında LifecycleOwner ayarlanmalıdır: binding.lifecycleOwner = viewLifecycleOwner.
// LiveData ile ViewModel
class WeatherViewModel : ViewModel() {
private val _temperature = MutableLiveData("--")
val temperature: LiveData<String> get() = _temperature
val cityName = MutableLiveData("Moskova")
val weatherIcon = MutableLiveData(R.drawable.ic_sunny)
fun refresh() {
viewModelScope.launch {
_temperature.value = weatherRepository.getTemperature()
}
}
}
// Fragment'te:
val binding = FragmentWeatherBinding.inflate(inflater, container, false)
binding.viewModel = weatherViewModel
binding.lifecycleOwner = viewLifecycleOwner // ← LiveData için gerekli
<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, lifecycle 2.5.0'dan itibaren Flow.asLiveData() veya doğrudan dönüştürme yoluyla StateFlow'u destekler. Data Binding'de StateFlow kullanırken binding.lifecycleOwner aracılığıyla yaşam döngüsünün ayarlandığından emin olun. LifecycleOwner ayarlanmazsa LiveData/StateFlow UI'yı güncellemez çünkü Binding abonenin ne zaman aktif olduğunu bilmez.
Avatar, ad, biyografi ve düzenleme düğmesi içeren tam bir profil ekranı. ViewModel reaktivite için ObservableField kullanır.
<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("Android geliştirici, 5 yıllık deneyim")
val avatarUrl = ObservableField("https://example.com/avatar.jpg")
val hasBio = ObservableBoolean(true)
fun onEdit() {
// Profil düzenleme mantığı
}
}
// Fragment'te:
val binding = FragmentProfileBinding.inflate(inflater, container, false)
binding.profile = profileViewModel
binding.lifecycleOwner = viewLifecycleOwner
Alan doğrulaması ve giriş düğmesi olan bir giriş formu. Çift yönlü bağlama (@={}) kullanıcı girişini ViewModel ile senkronize eder.
<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>
XML'de ifadeler kullanılır: düğme durumu (etkin/devre dışı) için @{login.isValid}, yükleme göstergesi için @{login.isLoading ? View.VISIBLE : View.GONE}, çift yönlü senkronizasyon için @{=login.email}. Tüm doğrulama mantığı ViewModel'de yaşar; View yalnızca durumu görüntüler. Google'a göre (Android Guide, 2025) bu yaklaşım UI mantığı hatalarının sayısını %50–60 oranında azaltır.
Sıkça Sorulan Sorular
Hayır, Jetpack Compose kendi reaktivite mekanizmasına (Composable işlevler + State) sahip bağımsız bir UI sistemidir. Data Binding yalnızca XML düzenleri için tasarlanmıştır ve Compose ile uyumlu değildir. XML'den Compose'a geçiş yaparken Data Binding kullanılmaz — bunun yerine mutableStateOf(), collectAsState() ve remember uygulanır. Data Binding yalnızca XML düzenlerini koruyan projeler için geçerliliğini korur.
İlk bağlama aşamasında Data Binding, ID'ye göre View araması yapar (findViewById gibi). Fark kullanıcı için fark edilemez: 20–30 View içeren tipik bir ekran 1–3 ms içinde bağlanır. Data Binding'in ana ek yükü derleme zamanındadır (ifade işleme). Çalışma zamanında çoğu ekran için Data Binding ve findViewById arasında fark yoktur. Binlerce öğeli RecyclerView için ViewBinding, daha az oluşturulan kod nedeniyle daha hızlı olabilir.
Data Binding ifadeleri derleme zamanında koda derler — hatalar Build Output'da XML satırı belirtilerek Compilation errors olarak görünür. Tipik hatalar: yanlış değişken türü, null güvenlik sorunları (varsayılan değerler için ?? kullanın), sınıf içe aktarma eksikliği. build.gradle (app)'de buildFeatures.dataBinding = true etkinleştirin ve <layout>'un XML kök etiketi olduğunu doğrulayın. Çalışma zamanı ifadelerinde hata ayıklamak için BindingAdapter'da BindingConversion ve günlük kaydı kullanın.
@BindingConversion, Data Binding ifadelerinde türleri otomatik olarak dönüştüren statik yöntemler için bir ek açıklamadır. Örneğin, Color Int'i ColorDrawable'a dönüştürme: @BindingConversion fun colorToDrawable(color: Int): ColorDrawable = ColorDrawable(color). Bundan sonra android:background="@{color.red}" otomatik olarak çalışacaktır. BindingConversion'lar küreseldir — projedeki tüm Binding ifadelerine uygulanır.
Hayır, Data Binding release derlemelerinde debug'da olduğu gibi çalışır. ProGuard/R8 optimizasyonu, Binding sınıfları doğrudan kullanılmazsa bunları kaldırabilir — kural ekleyin: -keep class * extends android.databinding.ViewDataBinding { *; }. Android Gradle Plugin 7.0'dan itibaren R8, ek kurallar olmadan Data Binding'i doğru şekilde işler. Release için Data Binding'i devre dışı bırakmak performansı artırmaz ancak onu kullanan tüm ekranları bozar.
Özet
@{} ve @={} ifadeleriyle XML'i verilere bildirimsel olarak bağlamak için Jetpack kütüphanesi.@={} — formlar için otomatik View ↔ ViewModel senkronizasyonu.lifecycleOwner aracılığıyla LiveData ve StateFlow'u yerel olarak destekler.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