Data Binding — Android Jetpack kitabxanası, XML layoutlarından UI komponentlərini deklarativ sintaksis vasitəsilə tətbiq kodundakı data mənbələri ilə birləşdirir. Əsasları izah edirik: Data Binding findViewById() şablon kodunu aradan qaldırır və data dəyişdikdə UI-nı avtomatik yeniləməyə imkan verir. Google məlumatlarına görə (Android Developers, 2025), Data Binding Android layihələrinin 45%-də istifadə olunur və LiveData və ya StateFlow ilə birlikdə əl ilə abunə idarəsi olmadan tam reaktiv bağlama təmin edir.
Əsas məqamlar
@={} vasitəsilə avtomatik data sinxronizasiyası.Data Binding — 2015-ci ildə Google I/O-da təqdim edilmiş və Android Gradle Plugin 1.5-də sabitləşmiş dəstək kitabxanasıdır (Android Jetpack). O, UI komponentlərini XML-də Activity və ya Fragment kodunda findViewById() çağırmadan birbaşa layout daxilində data mənbələri (POJO, ViewModel, LiveData) ilə bağlamağa imkan verir.
İş prinsipi: XML layout <layout> teqinə bükülür, orada data tipi ilə <variable> elan edilir. Layout daxilində data əyri mötərizələrdə ifadələr vasitəsilə yerləşdirilir @{}. Kompilasiya mərhələsində Android Gradle Plugin düzgün tiplərlə View-ə birbaşa istinadlar və data qurma metodları olan Binding sinfi (məsələn, ActivityMainBinding) yaradır.
Android Developers sorğusuna görə (2024), Data Binding bağlama məntiqini XML-ə köçürməklə Activity/Fragment-də UI kodunun həcmini 30–50% azaldır. Yanlış View tipi ilə bağlı səhvlərin sayı (findViewById()-də ClassCastException) sıfıra enir, çünki bütün tiplər kompilasiya mərhələsində yoxlanılır.
ViewBinding — Android Studio 3.6-da (2020) ortaya çıxmış Data Binding-in daha yüngül alternatividir. ViewBinding hər layout faylı üçün Binding sinfi yaradır, lakin ifadələr, dəyişənlər və reaktivlik dəstəyi olmadan. Əsas meyarlara görə müqayisə:
| Meyar | Data Binding | ViewBinding |
|---|---|---|
| Binding sinfinin yaradılması | Bəli | Bəli |
| XML-də ifadələr (@{}) | Bəli | Xeyr |
| İkitərəfli bağlama | Bəli | Xeyr |
| Reaktiv (LiveData) | Bəli | Xeyr |
| @BindingAdapter | Bəli | Xeyr |
| Kompilasiya sürəti | Daha yavaş (ifadələrin işlənməsi) | Daha sürətli |
| Mürəkkəblik | Yüksək | Aşağı |
Google tövsiyəsi (Android Developers, 2025): əksər layihələr üçün ViewBinding kifayətdir — Data Binding-in əlavə yüklənməsi olmadan View-ə type-safe giriş təmin edir. Data Binding-i seçin, əgər lazımdırsa: (1) XML-dən LiveData/StateFlow ilə reaktiv bağlama, (2) formalar üçün ikitərəfli bağlama, (3) xüsusi atributlar üçün BindingAdapter, (4) formatlaşdırma üçün XML-də ifadələr. IT Sectr-də sadə ekranlar üçün ViewBinding, mürəkkəb formalar və panellər üçün Data Binding istifadə edirik.
Tək tərəfli bağlama (@{}) data mənbədən (ViewModel) View-ə ötürür. İkitərəfli bağlama (@={}) datanı hər iki istiqamətdə sinxronlaşdırır: View-də dəyişiklik (mətn daxil etmə, Switch keçidi) avtomatik olaraq mənbəyi yeniləyir.
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="com.example.app.LoginViewModel" />
</data>
<LinearLayout ...>
<!-- Bir tərəfli: ViewModel-dən TextView-ə data -->
<TextView
android:text="@{viewModel.userName}" />
<!-- İkitərəfli: EditText dəyişiklikləri → ViewModel, ViewModel → EditText -->
<EditText
android:text="@{=viewModel.email}" />
<CheckBox
android:checked="@{=viewModel.agreeToTerms}" />
</LinearLayout>
</layout>
İkitərəfli bağlama üçün ViewModel ObservableField, LiveData və ya StateFlow istifadə etməlidir. İstifadəçi girişi ilə data dəyişdikdə Data Binding avtomatik olaraq mənbənin setterini çağırır. Vacib: ikitərəfli bağlama @InverseBindingAdapter təyin edilmiş atributlarla işləyir. Android daxili adapterlər təqdim edir: text, checked, visibility, progress, rating və digər standart atributlar üçün.
@BindingAdapter — Kotlin extension funksiyaları üçün annotasiya, istənilən View atributu üçün xüsusi bağlama məntiqini təyin etməyə imkan verir. Məsələn, XML-də URL göstərildikdə Glide vasitəsilə şəkil yükləmək və ya TextView ilə bağlamada tarixi formatlaşdırmaq.
// URL üzrə şəkil yükləmək üçün BindingAdapter
@BindingAdapter("imageUrl")
fun ImageView.setImageUrl(url: String?) {
Glide.with(this.context)
.load(url)
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.into(this)
}
// Çoxlu atributlarla BindingAdapter
@BindingAdapter("visibleGone")
fun View.setVisibleGone(visible: Boolean) {
visibility = if (visible) View.VISIBLE else View.GONE
}
// Çevirici ilə BindingAdapter (formatDate)
@BindingAdapter("formattedDate")
fun TextView.setFormattedDate(timestamp: Long) {
text = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()).format(Date(timestamp))
}
<!-- XML-də BindingAdapter istifadəsi -->
<ImageView
imageUrl="@{user.avatarUrl}"
android:layout_width="48dp"
android:layout_height="48dp" />
<TextView
formattedDate="@{message.createdAt}"
visibleGone="@{message.isVisible}" />
@BindingAdapter çoxlu atribut qəbul edə bilər (requireAll = true/false), bu da dəyərləri birləşdirməyə imkan verir. Məsələn, @BindingAdapter("imageUrl", "circleCrop") — əgər circleCrop true-dirsə, Glide CircleCrop transformasiyasını tətbiq edir. Google məlumatlarına görə (Android Performance, 2024), Data Binding-də Glide ilə BindingAdapter RecyclerView sürüşdürməsində saniyədə 60 kadra qədər işləyir, çünki asinxron yükləmə UI threadini bloklamır.
Data Binding LiveData-nı native dəstəkləyir Android Architecture Components 1.0 versiyasından. Layoutda dəyişən LiveData tipinə malikdirsə, Binding avtomatik olaraq ona abunə olur və qiymət dəyişdikdə UI-nı yeniləyir. Düzgün işləmə üçün Binding sinfində LifecycleOwner təyin edilməlidir: binding.lifecycleOwner = viewLifecycleOwner.
// LiveData ilə ViewModel
class WeatherViewModel : ViewModel() {
private val _temperature = MutableLiveData("--")
val temperature: LiveData<String> get() = _temperature
val cityName = MutableLiveData("Moskva")
val weatherIcon = MutableLiveData(R.drawable.ic_sunny)
fun refresh() {
viewModelScope.launch {
_temperature.value = weatherRepository.getTemperature()
}
}
}
// Fragment-də:
val binding = FragmentWeatherBinding.inflate(inflater, container, false)
binding.viewModel = weatherViewModel
binding.lifecycleOwner = viewLifecycleOwner // ← LiveData üçün məcburi
<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 StateFlow-u lifecycle 2.5.0-dan Flow.asLiveData() və ya birbaşa konvertasiya vasitəsilə dəstəkləyir. Data Binding-də StateFlow istifadə edərkən binding.lifecycleOwner vasitəsilə həyat dövrünün təyin olunduğuna əmin olun. LifecycleOwner təyin olunmadan LiveData/StateFlow UI-nı yeniləməyəcək, çünki Binding abunəçinin nə vaxt aktiv olduğunu bilmir.
Avatar, ad, bio və redaktə düyməsi ilə tam profil ekranı. ViewModel reaktivlik üçün ObservableField istifadə edir.
<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-developer, 5 il təcrübə")
val avatarUrl = ObservableField("https://example.com/avatar.jpg")
val hasBio = ObservableBoolean(true)
fun onEdit() {
// Profil redaktə məntiqi
}
}
// Fragment-də:
val binding = FragmentProfileBinding.inflate(inflater, container, false)
binding.profile = profileViewModel
binding.lifecycleOwner = viewLifecycleOwner
Sahə validasiyası və giriş düyməsi ilə giriş forması. İkitərəfli bağlama (@={}) istifadəçi girişini ViewModel ilə sinxronlaşdırır.
<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-də ifadələr istifadə olunur: düymə vəziyyəti üçün @{login.isValid} (aktiv/aktiv deyil), yükləmə göstəricisi üçün @{login.isLoading ? View.VISIBLE : View.GONE}, ikitərəfli sinxronizasiya üçün @{=login.email}. Bütün validasiya məntiqi ViewModel-də yaşayır, View yalnız vəziyyəti göstərir. Google məlumatlarına görə (Android Guide, 2025), bu yanaşma UI məntiqindəki səhvlərin sayını 50–60% azaldır.
Tez-tez verilən suallar
Xeyr, Jetpack Compose öz reaktivlik mexanizmi (Composable funksiyaları + State) olan müstəqil UI sistemidir. Data Binding yalnız XML layoutları üçün nəzərdə tutulub və Compose ilə uyğun deyil. XML-dən Compose-a miqrasiya zamanı Data Binding istifadə edilmir — onun əvəzinə mutableStateOf(), collectAsState() və remember tətbiq olunur. Data Binding yalnız XML layoutlarını qoruyan layihələr üçün aktual qalır.
İlk bağlama mərhələsində Data Binding View-i ID ilə axtarır (findViewById kimi). Fərq istifadəçi üçün nəzərə çarpmır: 20–30 View olan tipik ekran 1–3 ms-də bağlanır. Data Binding-in əsas əlavə yüklənməsi kompilasiya mərhələsindədir (ifadələrin işlənməsi). Runtime-da Data Binding və findViewById arasında fərq əksər ekranlar üçün yoxdur. Minlərlə elementi olan RecyclerView üçün ViewBinding daha az kod yaradıldığından daha sürətli ola bilər.
Data Binding ifadələri qurma mərhələsində koda kompilə edir — səhvlər Build Output-da XML sətri göstərilməklə Compilation errors kimi göstərilir. Tipik səhvlər: yanlış dəyişən tipi, null-təhlükəsizlik (default dəyərlər üçün ?? istifadə edin), sinif importunun olmaması. build.gradle (app)-də buildFeatures.dataBinding = true aktiv edin və <layout>-un XML-in kök teqi olduğunu yoxlayın. Runtime ifadələrini debug etmək üçün BindingConversion və BindingAdapter-də loglamadan istifadə edin.
@BindingConversion — statik metodlar üçün annotasiya, Data Binding ifadələrində tipləri avtomatik çevirir. Məsələn, Color Int-i ColorDrawable-a çevirmək: @BindingConversion fun colorToDrawable(color: Int): ColorDrawable = ColorDrawable(color). Bundan sonra android:background="@{color.red}" avtomatik işləyəcək. BindingConversion qlobaldır — layihədəki bütün Binding ifadələrinə tətbiq olunur.
Xeyr, Data Binding release qurmasında debugda olduğu kimi işləyir. ProGuard/R8 optimallaşdırması Binding siniflərini silə bilər, əgər birbaşa istifadə edilmirsə — qayda əlavə edin: -keep class * extends android.databinding.ViewDataBinding { *; }. Android Gradle Plugin 7.0-dan başlayaraq, R8 Data Binding-i əlavə qaydalar olmadan düzgün emal edir. Release üçün Data Binding-in söndürülməsi performans artımı vermir, lakin ondan istifadə edən bütün ekranları sındırır.
Nəticə
@{} və @={} ifadələri vasitəsilə data ilə deklarativ bağlamaq üçün Jetpack kitabxanası.@={} — formalar üçün View ↔ ViewModel avtomatik sinxronizasiyası.lifecycleOwner vasitəsilə native dəstəkləyir.Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun