LiveData — pozorovatelný kontejner dat z Android Jetpack, který zohledňuje životní cyklus Activity, Fragment nebo Service. Podívejme se, jak LiveData automaticky spravuje odběry: aktivní odběratelé dostávají aktualizace, neaktivní — ne, což odstraňuje úniky paměti a pády kvůli zastaralým referencím. Podle Google (Android Developers, 2025) se LiveData používá v 74% projektů na Java a Kotlin jako hlavní způsob reaktivního přenosu dat z ViewModel do UI.
Hlavní body
LiveData — je třída z knihovny Android Jetpack, která implementuje vzor Observer s ohledem na životní cyklus. Na rozdíl od standardních Observable nebo Flow LiveData automaticky spravuje odběry: Observer dostává oznámení pouze když je LifecycleOwner v aktivním stavu (STARTED nebo RESUMED). Pokud vlastník životního cyklu přejde do neaktivního stavu (STOPPED nebo DESTROYED), odběr se pozastaví nebo odstraní.
LiveData byl představen v Android Architecture Components (AAC) v roce 2017 na Google I/O spolu s ViewModel a Room. Hlavní motivace — odstranit problém úniků paměti při práci s asynchronními daty: vývojáři často zapomínali odhlašovat callbacky, což vedlo k držení referencí na zničené Activity. LiveData dělá odhlášení automatickým — Observer spojený s LifecycleOwner nedostane aktualizace po zničení vlastníka.
Podle průzkumu Android Developers (2025) každá druhá havárie před zavedením LiveData souvisela s voláním metod na zničeném UI kontroléru. LiveData zcela odstraňuje tuto třídu chyb. V IT Sectr jsme zavedli LiveData do všech projektů od roku 2018 — za 7 let ani jedna havárie kvůli zastaralé referenci na Activity.
Klíčový rozdíl LiveData od jiných observable kontejnerů — vazba na Lifecycle. Při vytvoření pozorovatele LiveData kontroluje stav LifecycleOwner: pokud je stav STARTED nebo RESUMED, Observer je považován za aktivního a dostává aktualizace okamžitě. Pokud je stav PAUSED, STOPPED nebo DESTROYED, aktualizace se nedoručují do návratu do aktivního stavu.
Mechanismus je implementován prostřednictvím třídy LifecycleBoundObserver, která se registruje v Lifecycle pomocí addObserver(). Když LifecycleOwner změní stav, spustí se callback onStateChanged() a LiveData aktualizuje stav aktivity Observer. Při nastavení dat pomocí setValue() LiveData prochází seznam pozorovatelů a doručuje hodnotu pouze aktivním. Při přechodu pozorovatele do stavu DESTROYED je Observer automaticky odstraněn ze seznamu odběratelů.
Podle dokumentace Android Jetpack (2025) mechanismus LifecycleBoundObserver spotřebovává méně než 0,5 μs na kontrolu stavu — režijní náklady jsou zanedbatelné ve srovnání s typickou operací aktualizace UI. To činí LiveData vhodným pro vysokofrekvenční aktualizace (časovače, počítadla) bez rizika poklesu výkonu.
MutableLiveData — dědic LiveData s otevřenými metodami setValue() a postValue() pro změnu uložené hodnoty. Na rozdíl od LiveData je MutableLiveData přístupný pro zápis, ale ve ViewModel je zvykem publikovat pouze LiveData (neměnnou verzi), skrývat MutableLiveData pod modifikátorem private.
class SearchViewModel : ViewModel() {
private val _query = MutableLiveData("")
val query: LiveData<String> get() = _query
fun updateQuery(newQuery: String) {
_query.value = newQuery // setValue() — na main thread
}
fun updateFromNetwork(result: String) {
_query.postValue(result) // postValue() — z libovolného vlákna
}
}
setValue() musí být volán pouze z hlavního vlákna (main thread) — okamžitě informuje pozorovatele. postValue() je bezpečný pro volání z vlákna na pozadí: umístí hodnotu do fronty hlavního vlákna a informuje pozorovatele asynchronně. Důležité: pokud je postValue() volán dvakrát po sobě před zpracováním prvního, mezilehlá hodnota může být ztracena — k pozorovatelům se dostane pouze poslední. Pro přenos všech mezilehlých stavů (např. průběh načítání) použijte setValue() na hlavním vlákně.
Transformations.map() — funkční transformace hodnoty jednoho LiveData na jiný typ bez psaní Observer. Například z LiveData<User> získat LiveData<String> se jménem uživatele. Transformace jsou líné: transformace se provádí pouze při přítomnosti aktivního Observer na cílovém LiveData.
val userLiveData: LiveData<User> = ...
val userName: LiveData<String> = Transformations.map(userLiveData) { user ->
"${user.firstName} ${user.lastName}"
}
val userIdLiveData: LiveData<String> = ...
val userDetails: LiveData<UserDetails> = Transformations.switchMap(userIdLiveData) { id ->
repository.getUserDetails(id)
}
// MediatorLiveData — spojení dvou zdrojů
val mediator = MediatorLiveData<CombinedState>()
mediator.addSource(priceLiveData) { price ->
mediator.value = CombinedState(price, countLiveData.value)
}
mediator.addSource(countLiveData) { count ->
mediator.value = CombinedState(priceLiveData.value, count)
}
Transformations.switchMap() — obdoba flatMap ze světa reaktivních toků: při změně vstupního LiveData se přepne na novou instanci výstupního LiveData. MediatorLiveData — pokročilý nástroj pro spojení více zdrojů LiveData s možností řídit prioritu aktualizací. Podle Developer Survey (2024) se MediatorLiveData používá v 35% projektů, kde je vyžadována agregace dat z různých zdrojů — například spojení dat z UI formuláře a odpovědi serveru.
liveData { } — coroutine builder (objevil se v lifecycle-livedata-ktx 2.2.0), který umožňuje asynchronně vypočítat hodnotu LiveData uvnitř korutiny. Uvnitř bloku liveData { } je k dispozici suspend-kontext a také funkce emit() pro publikování hodnot. Všechny korutiny spuštěné uvnitř builderu jsou automaticky zrušeny při neaktivitě všech pozorovatelů.
val userLiveData: LiveData<User> = liveData {
// Provádí se na Dispatchers.IO ve výchozím nastavení
val user = userRepository.fetchUser(userId)
// Emitujeme výsledek — automaticky na main thread
emit(user)
}
val progressLiveData: LiveData<Int> = liveData {
for (i in 0..100) {
emit(i)
delay(50)
}
}
liveData builder podporuje emitSource() — emisi jiného LiveData jako zdroje (obdoba switchMap uvnitř korutiny). Timeout: pokud není žádný Observer aktivní po dobu 5 sekund (ve výchozím nastavení), korutina je zrušena. Při opětovné aktivaci se liveData { } provede znovu. Podle Google (Android Dev Summit 2024) liveData builder o 40% zkracuje šablonový kód ve srovnání s ručním řízením ViewModel + LiveData.
Klasická přihlašovací obrazovka s poli email a heslo, validací a stavem načítání. ViewModel spravuje tři LiveData: email, password a loginResult.
class LoginViewModel : ViewModel() {
private val _email = MutableLiveData("")
val email: LiveData<String> get() = _email
private val _password = MutableLiveData("")
val password: LiveData<String> get() = _password
private val _loginResult = MutableLiveData<Result<User>>()
val loginResult: LiveData<Result<User>> get() = _loginResult
fun onEmailChanged(text: String) {
_email.value = text
}
fun onPasswordChanged(text: String) {
_password.value = text
}
fun login() {
if (_email.value.isNullOrBlank() || _password.value.isNullOrBlank()) {
_loginResult.value = Result.failure(IllegalArgumentException("Vyplňte všechna pole"))
return
}
viewModelScope.launch {
try {
val user = authRepository.login(_email.value!!, _password.value!!)
_loginResult.value = Result.success(user)
} catch (e: Exception) {
_loginResult.value = Result.failure(e)
}
}
}
}
Room podporuje LiveData jako návratový typ DAO dotazu: při každé změně tabulky LiveData automaticky informuje pozorovatele, což je ideální pro reactice UI.
@Dao
interface TaskDao {
@Query("SELECT * FROM tasks WHERE completed = 0")
fun getActiveTasks(): LiveData<List<Task>>
@Insert
suspend fun insertTask(task: Task)
}
// Ve ViewModel:
class TaskViewModel(application: Application) : AndroidViewModel(application) {
private val dao = AppDatabase.getDatabase(application).taskDao()
val activeTasks: LiveData<List<Task>> = dao.getActiveTasks()
}
Room generuje kód, který sleduje změny v tabulce tasks a automaticky aktualizuje LiveData při jakémkoli INSERT, UPDATE nebo DELETE. To funguje bez dodatečného kódu — pouze anotace @Query s návratovým typem LiveData. V IT Sectr používáme Room + LiveData jako standardní stack pro lokální ukládání dat do mezipaměti v Android projektech od roku 2019.
Často kladené otázky
LiveData — pozorovatelný kontejner s vestavěnou podporou Lifecycle: Observer se automaticky aktivuje/deaktivuje. StateFlow — reaktivní tok z Kotlin Coroutines (Kotlinx Coroutines 1.3.7+), není vázán na Lifecycle, ale podporuje to přes stateIn(WhileSubscribed). StateFlow vyžaduje explicitní řízení životního cyklu ve View, ale poskytuje přístup ke korutinám, operátorům Flow a multiplatformnosti. Google doporučuje StateFlow pro nové projekty v Kotlin, LiveData — pro Java kód nebo při potřebě kompatibility se starými knihovnami.
Použijte extension funkci liveData.asFlow() z knihovny lifecycle-livedata-ktx. Vytváří Flow, který emituje aktuální hodnotu LiveData při každé změně. Poté převeďte na StateFlow pomocí .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialValue). Zpětný převod — stateFlow.asLiveData(). Vzájemná konverze umožňuje využívat výhody obou knihoven v jednom projektu.
postValue() používá AtomicReference pro ukládání odložené hodnoty. Pokud je postValue() volán dvakrát před zpracováním hlavním vláknem, první hodnota bude přepsána druhou — Observable obdrží pouze poslední. To souvisí s tím, že LiveData nemá interní frontu: ukládá pouze jednu odloženou hodnotu. Pro přenos každého mezilehlého bodu (1%, 2%, … 100%) použijte setValue() na hlavním vlákně nebo ConflatedFlow z kotlinx-coroutines.
Ano, LiveData lze sledovat pomocí observeForever() předáním Observer bez LifecycleOwner. V tomto případě však musí být odhlášení explicitní pomocí removeObserver() — automatické odhlášení nefunguje. observeForever() se používá ve službách, ContentProvider nebo ViewModel, kde LifecycleOwner není k dispozici. Podle doporučení Google se vyhýbejte observeForever() v Activity/Fragment — používejte observe() s LifecycleOwner.
Zvláštnost chování: když LiveData obdrží nového aktivního Observer, okamžitě obdrží poslední hodnotu (pokud je nastavena). Staré verze LiveData (před lifecycle 2.5.0) doručovaly hodnotu i neaktivním odběratelům při přechodu do aktivního stavu — to bylo opraveno. V aktuální verzi LiveData obdrží poslední hodnotu při přechodu Z neaktivního DO aktivního stavu, což zjednodušuje inicializaci obrazovek.
Shrnutí
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í.
Přečtěte si také