Data Binding — základy, obousměrné propojování v Android

Autor: IT Sectr Publikováno: 2026-02-20 Doba čtení: 8 min

Data Binding — knihovna Android Jetpack, která propojuje UI komponenty z XML rozvržení se zdroji dat v kódu aplikace pomocí deklarativní syntaxe. Vysvětlujeme základy: Data Binding odstraňuje standardní kód findViewById() a umožňuje automatickou aktualizaci UI při změně dat. Podle Google (Android Developers, 2025) je Data Binding používán ve 45% Android projektů a v kombinaci s LiveData nebo StateFlow poskytuje plně reaktivní propojení bez ruční správy odběrů.

Hlavní body

  • Data Binding — knihovna Jetpack pro deklarativní propojení XML rozvržení se zdroji dat pomocí layout tagů.
  • Obousměrné propojování — automatická synchronizace dat mezi View a ViewModel přes @={} v XML.
  • @BindingAdapter — vlastní setter pro atributy View, umožňující rozšíření standardního Data Binding.
  • Data Binding + LiveData — reaktivita bez Observer: změny LiveData automaticky aktualizují UI.
  • Data Binding generuje třídu Binding (např. ActivityMainBinding) při kompilaci a poskytuje type-safe přístup k View.

Co je Data Binding v Android?

Data Binding — podpůrná knihovna (Android Jetpack), která se objevila v roce 2015 na Google I/O a byla stabilizována v Android Gradle Plugin 1.5. Umožňuje propojovat UI komponenty v XML se zdroji dat (POJO, ViewModel, LiveData) přímo v rozvržení, bez volání findViewById() v kódu Activity nebo Fragment.

Princip fungování: XML rozvržení je zabaleno do tagu <layout>, ve kterém je deklarována proměnná <variable> s datovým typem. Uvnitř rozvržení jsou data dosazována pomocí výrazů ve složených závorkách @{}. Při kompilaci Android Gradle Plugin vygeneruje třídu Binding (např. ActivityMainBinding) obsahující přímé reference na View se správnými typy a metody pro nastavení dat.

Podle průzkumu Android Developers (2024) Data Binding snižuje objem UI kódu v Activity/Fragment o 30–50% díky přesunu logiky propojování do XML. Počet chyb spojených s nesprávným typem View (ClassCastException při findViewById()) klesá na nulu, protože všechny typy jsou kontrolovány při kompilaci.

Data Binding vs ViewBinding: co vybrat

ViewBinding — lehčí alternativa Data Binding, která se objevila v Android Studio 3.6 (2020). ViewBinding generuje třídu Binding pro každý soubor layout, ale bez podpory výrazů, proměnných a reaktivity. Srovnání podle klíčových kritérií:

KritériumData BindingViewBinding
Generování třídy BindingAnoAno
Výrazy v XML (@{})AnoNe
Obousměrné propojováníAnoNe
Reaktivní (LiveData)AnoNe
@BindingAdapterAnoNe
Rychlost kompilacePomalejší (zpracování výrazů)Rychlejší
SložitostVysokáNízká

Doporučení Google (Android Developers, 2025): pro většinu projektů stačí ViewBinding — poskytuje type-safe přístup k View bez režie Data Binding. Data Binding zvolte, pokud potřebujete: (1) reaktivní propojení s LiveData/StateFlow z XML, (2) obousměrné propojení pro formuláře, (3) BindingAdapter pro vlastní atributy, (4) výrazy v XML pro formátování. V IT Sectr používáme ViewBinding pro jednoduché obrazovky a Data Binding pro složité formuláře a dashboardy.

Obousměrné propojování: @{} a @={}

Jednosměrné propojování (@{}) přenáší data ze zdroje (ViewModel) do View. Obousměrné propojování (@={}) synchronizuje data v obou směrech: změna ve View (vstup textu, přepnutí Switch) automaticky aktualizuje zdroj.

xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="viewModel"
            type="com.example.app.LoginViewModel" />
    </data>

    <LinearLayout ...>
        <!-- Jednosměrné: data z ViewModel do TextView -->
        <TextView
            android:text="@{viewModel.userName}" />

        <!-- Obousměrné: změny EditText → ViewModel, ViewModel → EditText -->
        <EditText
            android:text="@{=viewModel.email}" />

        <CheckBox
            android:checked="@{=viewModel.agreeToTerms}" />
    </LinearLayout>
</layout>

Pro obousměrné propojování musí ViewModel používat ObservableField, LiveData nebo StateFlow. Při změně dat prostřednictvím vstupu uživatele Data Binding automaticky volá setter zdroje. Důležité: obousměrné propojování funguje s atributy, pro které je definován @InverseBindingAdapter. Android poskytuje vestavěné adaptéry pro: text, checked, visibility, progress, rating a další standardní atributy.

@BindingAdapter: vlastní atributy a převodníky

@BindingAdapter — anotace pro Kotlin extension funkce, umožňující definovat vlastní logiku propojení pro libovolný atribut View. Například načtení obrázku přes Glide při zadání URL v XML, nebo formátování data při propojení s TextView.

kotlin
// BindingAdapter pro načtení obrázku z 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 s více atributy
@BindingAdapter("visibleGone")
fun View.setVisibleGone(visible: Boolean) {
    visibility = if (visible) View.VISIBLE else View.GONE
}

// BindingAdapter s převodníkem (formatDate)
@BindingAdapter("formattedDate")
fun TextView.setFormattedDate(timestamp: Long) {
    text = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()).format(Date(timestamp))
}
xml
<!-- Použití BindingAdapter v XML -->
<ImageView
    imageUrl="@{user.avatarUrl}"
    android:layout_width="48dp"
    android:layout_height="48dp" />

<TextView
    formattedDate="@{message.createdAt}"
    visibleGone="@{message.isVisible}" />

@BindingAdapter může přijímat více atributů (requireAll = true/false), což umožňuje kombinovat hodnoty. Například @BindingAdapter("imageUrl", "circleCrop") — pokud je circleCrop true, Glide aplikuje transformaci CircleCrop. Podle Google (Android Performance, 2024) BindingAdapter s Glide v Data Binding zpracovává až 60 snímků za sekundu při posouvání RecyclerView, protože asynchronní načítání neblokuje UI vlákno.

Data Binding s LiveData a StateFlow

Data Binding nativně podporuje LiveData od verze Android Architecture Components 1.0. Pokud má proměnná v rozvržení typ LiveData, Binding se na ni automaticky přihlásí a aktualizuje UI při změně hodnoty. Pro správnou funkci je nutné nastavit LifecycleOwner ve třídě Binding: binding.lifecycleOwner = viewLifecycleOwner.

kotlin
// ViewModel s LiveData
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()
        }
    }
}

// Ve Fragment:
val binding = FragmentWeatherBinding.inflate(inflater, container, false)
binding.viewModel = weatherViewModel
binding.lifecycleOwner = viewLifecycleOwner  // ← povinné pro LiveData
xml
<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 podporuje StateFlow od lifecycle 2.5.0 přes Flow.asLiveData() nebo přímou konverzi. Při použití StateFlow v Data Binding se ujistěte, že je životní cyklus nastaven přes binding.lifecycleOwner. Bez LifecycleOwner nebudou LiveData/StateFlow aktualizovat UI, protože Binding neví, kdy je odběratel aktivní.

Příklady kódu: Data Binding v Kotlin a XML

Příklad 1: Obrazovka profilu s Data Binding

Plná obrazovka profilu s avatarem, jménem, bio a tlačítkem pro úpravu. ViewModel používá ObservableField pro reaktivitu.

xml
<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>
kotlin
class ProfileViewModel : ViewModel() {
    val name = ObservableField("Anna Petrova")
    val bio = ObservableField("Android-vývojář, 5 let zkušeností")
    val avatarUrl = ObservableField("https://example.com/avatar.jpg")
    val hasBio = ObservableBoolean(true)

    fun onEdit() {
        // Logika úpravy profilu
    }
}

// Ve Fragment:
val binding = FragmentProfileBinding.inflate(inflater, container, false)
binding.profile = profileViewModel
binding.lifecycleOwner = viewLifecycleOwner

Příklad 2: Přihlašovací formulář s obousměrným propojením

Přihlašovací formulář s validací polí a tlačítkem pro přihlášení. Obousměrné propojení (@={}) synchronizuje vstup uživatele s ViewModel.

xml
<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>

V XML se používají výrazy: @{login.isValid} pro stav tlačítka (aktivní/neaktivní), @{login.isLoading ? View.VISIBLE : View.GONE} pro indikátor načítání, @{=login.email} pro obousměrnou synchronizaci. Veškerá logika validace žije ve ViewModel, View pouze zobrazuje stav. Podle Google (Android Guide, 2025) tento přístup snižuje počet chyb v UI logice o 50–60%.

Často kladené otázky

Lze použít Data Binding s Compose?

Ne, Jetpack Compose je samostatný UI systém s vlastním mechanismem reaktivity (Composable funkce + State). Data Binding je určen výhradně pro XML rozvržení a není kompatibilní s Compose. Při migraci z XML na Compose se Data Binding nepoužívá — místo něj se aplikuje mutableStateOf(), collectAsState() a remember. Data Binding zůstává relevantní pouze pro projekty zachovávající XML rozvržení.

Je Data Binding pomalejší než findViewById?

Při prvním propojení Data Binding vyhledává View podle ID (jako findViewById). Rozdíl je pro uživatele nepostřehnutelný: typická obrazovka s 20–30 View se propojí za 1–3 ms. Hlavní režie Data Binding je ve fázi kompilace (zpracování výrazů). Za běhu rozdíl mezi Data Binding a findViewById u většiny obrazovek neexistuje. Pro RecyclerView s tisíci položkami může být ViewBinding rychlejší díky menšímu množství generovaného kódu.

Jak odladit chybu Data Binding?

Data Binding kompiluje výrazy do kódu při sestavení — chyby se zobrazují v Build Output jako Compilation errors s uvedením řádku XML. Typické chyby: nesprávný typ proměnné, null-bezpečnost (použijte ?? pro výchozí hodnoty), chybějící import třídy. Povolte buildFeatures.dataBinding = true v build.gradle (app) a zkontrolujte, že <layout> je kořenový tag XML. Pro ladění výrazů za běhu použijte BindingConversion a logování v BindingAdapter.

Co je BindingConversion?

@BindingConversion — anotace pro statické metody, která automaticky převádí typy ve výrazech Data Binding. Například převod Color Int na ColorDrawable: @BindingConversion fun colorToDrawable(color: Int): ColorDrawable = ColorDrawable(color). Poté bude android:background="@{color.red}" fungovat automaticky. BindingConversion jsou globální — vztahují se na všechny Binding výrazy v projektu.

Je třeba vypnout Data Binding pro release sestavení?

Ne, Data Binding funguje v release sestavení stejně jako v debug. Optimalizace ProGuard/R8 může odstranit Binding třídy, pokud nejsou přímo používány — přidejte pravidlo: -keep class * extends android.databinding.ViewDataBinding { *; }. Od Android Gradle Plugin 7.0 R8 správně zpracovává Data Binding bez dalších pravidel. Vypnutí Data Binding pro release nepřináší zvýšení výkonu, ale rozbíjí všechny obrazovky, které jej používají.

Shrnutí

  • Data Binding — knihovna Jetpack pro deklarativní propojení XML s daty pomocí výrazů @{} a @={}.
  • Generuje type-safe Binding třídy, odstraňuje findViewById() a ClassCastException.
  • ViewBinding — lehká alternativa bez výrazů; Data Binding volte pro reaktivní a složitá UI.
  • Obousměrné propojování @={} — automatická synchronizace View ↔ ViewModel pro formuláře.
  • @BindingAdapter — vlastní atributy (načítání obrázků, formátování, viditelnost).
  • Data Binding nativně podporuje LiveData a StateFlow přes lifecycleOwner.
  • Data Binding snižuje UI kód o 30–50% a snižuje počet chyb propojení na nulu.

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také