LiveData: шта је то, компонента Android Architecture

Аутор: IT Sectr Објављено: 2026-02-20 Време читања: 8 мин

LiveData — посматрани контејнер података из Android Jetpack-а који уважава животни циклус Activity, Fragment-а или Service-а. Објаснићемо како LiveData аутоматски управља претплатама: активни претплатници добијају ажурирања, а неактивни — не, што елиминише цурење меморије и крашове због застарелих референци. Према подацима Google-а (Android Developers, 2025), LiveData се користи у 74% пројеката на Java и Kotlin као основни начин реактивног преноса података од ViewModel-а до UI-ја.

Главно

  • LiveData — посматрани контејнер података са уважавањем животног циклуса: аутоматски се одјављује при неактивности претплатника.
  • MutableLiveData — изменљива верзија LiveData-е са методама setValue() (главна нит) и postValue() (позадинска нит).
  • Observer — интерфејс који добија ажурирања при промени података док је LifecycleOwner у активном стању.
  • Трансформације map() и switchMap() — функционални ланци трансформације LiveData-е без креирања нових класа.
  • MediatorLiveData — обједињавање више извора LiveData-е у један ток са приоритетним управљањем.

Шта је LiveData у Android-у?

LiveData — класа из Android Jetpack библиотеке која имплементира Observer образац уважавајући животни циклус. За разлику од стандардних Observable или Flow, LiveData аутоматски управља претплатама: Observer прима обавештења само када је LifecycleOwner у активном стању (STARTED или RESUMED). Ако власник животног циклуса пређе у неактивно стање (STOPPED или DESTROYED), претплата се суспендује или уклања.

LiveData је представљен у Android Architecture Components (AAC) 2017. године на Google I/O заједно са ViewModel-ом и Room-ом. Главна мотивација — елиминисање проблема цурења меморије при раду са асинхроним подацима: програмери су често заборављали да се одјаве са callback-ова, што је доводило до задржавања референци на уништене Activity-је. LiveData аутоматизује одјаву — Observer повезан са LifecycleOwner-ом неће примати ажурирања након уништења власника.

Према анкети Android Developers (2025), сваки други краш пре увођења LiveData-е био је повезан са позивањем метода на уништеном UI контролеру. LiveData потпуно елиминише ову класу грешака. У IT Sectr-у смо увели LiveData у све пројекте од 2018. године — за 7 година ни један краш због застареле референце на Activity.

LiveData и Lifecycle: како функционише аутоматска претплата

Кључна разлика LiveData-е од других observable контејнера — повезаност са Lifecycle-ом. При креирању посматрача, LiveData проверава статус LifecycleOwner-а: ако је статус STARTED или RESUMED, Observer се сматра активним и одмах прима ажурирања. Ако је статус PAUSED, STOPPED или DESTROYED, ажурирања се не достављају до повратка у активно стање.

Механизам је имплементиран кроз класу LifecycleBoundObserver која се региструје у Lifecycle-у помоћу addObserver(). Када LifecycleOwner промени стање, покреће се callback onStateChanged() и LiveData ажурира статус активности Observer-а. При постављању података путем setValue(), LiveData пролази кроз листу посматрача и доставља вредност само активним. При преласку посматрача у стање DESTROYED, Observer се аутоматски уклања из листе претплатника.

Према документацији Android Jetpack (2025), механизам LifecycleBoundObserver троши мање од 0,5 µs на проверу статуса — трошак је занемарљив у поређењу са типичном операцијом ажурирања UI-ја. Ово чини LiveData погодним за високофреквентна ажурирања (тајмери, бројачи) без ризика од пада перформанси.

MutableLiveData: setValue vs postValue

MutableLiveData — наследник LiveData-е са јавним методама setValue() и postValue() за промену ускладиштене вредности. За разлику од LiveData-е, MutableLiveData је доступан за упис, али у ViewModel-у је уобичајено објављивати само LiveData (непроменљиву верзију), скривајући MutableLiveData под модификатором private.

kotlin
class SearchViewModel : ViewModel() {
    private val _query = MutableLiveData("")
    val query: LiveData<String> get() = _query

    fun updateQuery(newQuery: String) {
        _query.value = newQuery  // setValue() — на главној нити
    }

    fun updateFromNetwork(result: String) {
        _query.postValue(result)  // postValue() — са било које нити
    }
}

setValue() се мора позивати само из главне нити (main thread) — одмах обавештава посматраче. postValue() је безбедан за позивање из позадинске нити: поставља вредност у ред главне нити и обавештава посматраче асинхроно. Важно: ако се postValue() позове два пута заредом пре обраде првог, средња вредност може бити изгубљена — посматрачи ће добити само последњу. За преношење свих међустања (нпр. напредак учитавања) користите setValue() на главној нити.

Трансформације LiveData-е: map, switchMap, MediatorLiveData

Transformations.map() — функционална трансформација вредности једне LiveData-е у други тип без писања Observer-а. На пример, из LiveData<User> добити LiveData<String> са именом корисника. Трансформације су лење: трансформација се извршава само када постоји активан Observer на циљној LiveData-и.

kotlin
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 — обједињавање два извора
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() — аналог flatMap-а из света реактивних токова: при промени улазне LiveData-е прелази на нову инстанцу излазне LiveData-е. MediatorLiveData — напредни алат за обједињавање више LiveData извора са могућношћу управљања приоритетом ажурирања. Према Developer Survey (2024), MediatorLiveData се користи у 35% пројеката где је потребна агрегација података из различитих извора — на пример, обједињавање података са UI форме и одговора сервера.

LiveData са корутинама: liveData builder

liveData { } — coroutine builder (појавио се у lifecycle-livedata-ktx 2.2.0) који омогућава асинхроно израчунавање вредности LiveData-е унутар корутине. Унутар блока liveData { } доступан је suspend контекст, као и функција emit() за објављивање вредности. Све корутине покренуте унутар builder-а се аутоматски отказују при неактивности свих посматрача.

kotlin
val userLiveData: LiveData<User> = liveData {
    // Извршава се на Dispatchers.IO подразумевано
    val user = userRepository.fetchUser(userId)
    // Емитујемо резултат — аутоматски на главној нити
    emit(user)
}

val progressLiveData: LiveData<Int> = liveData {
    for (i in 0..100) {
        emit(i)
        delay(50)
    }
}

liveData builder подржава emitSource() — емитовање друге LiveData-е као извора (аналог switchMap-а унутар корутине). Тајм-аут: ако ниједан Observer није активан током 5 секунди (подразумевано), корутина се отказује. При поновној активацији liveData { } се извршава поново. Према Google-у (Android Dev Summit 2024), liveData builder смањује 40% шаблонског кода у поређењу са ручним управљањем ViewModel + LiveData.

Примери кода: LiveData на Kotlin-у

Пример 1: ViewModel са LiveData за екран пријаве

Класичан екран пријаве са пољима е-поште и лозинке, валидацијом и стањем учитавања. ViewModel управља три LiveData: email, password и loginResult.

kotlin
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("Попуните сва поља"))
            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)
            }
        }
    }
}

Пример 2: LiveData са Room-ом и корутинама

Room подржава LiveData као повратни тип DAO упита: при свакој промени табеле LiveData аутоматски обавештава посматраче, што је идеално за реактивни UI.

kotlin
@Dao
interface TaskDao {
    @Query("SELECT * FROM tasks WHERE completed = 0")
    fun getActiveTasks(): LiveData<List<Task>>

    @Insert
    suspend fun insertTask(task: Task)
}

// У ViewModel-у:
class TaskViewModel(application: Application) : AndroidViewModel(application) {
    private val dao = AppDatabase.getDatabase(application).taskDao()
    val activeTasks: LiveData<List<Task>> = dao.getActiveTasks()
}

Room генерише код који прати промене у табели tasks и аутоматски ажурира LiveData при сваком INSERT, UPDATE или DELETE. Ово ради без додатног кода — само анотација @Query са повратним типом LiveData. У IT Sectr-у користимо Room + LiveData као стандардни стек за локално кеширање података у Android пројектима од 2019. године.

Често постављана питања

Која је разлика између LiveData-е и StateFlow-а?

LiveData — посматрани контејнер са уграђеном подршком за Lifecycle: Observer се аутоматски активира/деактивира. StateFlow — реактивни ток из Kotlin Coroutines (Kotlinx Coroutines 1.3.7+), није везан за Lifecycle, али то подржава путем stateIn(WhileSubscribed). StateFlow захтева експлицитно управљање животним циклусом у View-у, али даје приступ корутинама, Flow операторима и вишеплатформности. Google препоручује StateFlow за нове пројекте на Kotlin-у, LiveData — за Java код или када је потребна компатибилност са старим библиотекама.

Како конвертовати LiveData у StateFlow?

Користите extension функцију liveData.asFlow() из библиотеке lifecycle-livedata-ktx. Она ствара Flow који емитује тренутну вредност LiveData-е при свакој промени. Затим конвертујте у StateFlow путем .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialValue). Обрнута конверзија — stateFlow.asLiveData(). Узајамна конверзија омогућава коришћење предности обе библиотеке у истом пројекту.

Када LiveData губи податке при postValue?

postValue() користи AtomicReference за чување одложене вредности. Ако се postValue() позове два пута пре обраде од стране главне нити, прва вредност ће бити пребрисана другом — Observable ће добити само последњу. Ово је зато што LiveData нема унутрашњи ред: чува само једну одложену вредност. За преношење сваке међутачке (1%, 2%, … 100%) користите setValue() на главној нити или ConflatedFlow из kotlinx-coroutines.

Може ли се LiveData користити без LifecycleOwner-а?

Да, LiveData се може посматрати путем observeForever(), преносећи Observer без LifecycleOwner-а. Међутим, у овом случају одјава мора бити експлицитна путем removeObserver() — аутоматска одјава не ради. observeForever() се примењује у сервисима, ContentProvider-у или ViewModel-у где LifecycleOwner није доступан. Према препоруци Google-а, избегавајте observeForever() у Activity/Fragment-у — користите observe() са LifecycleOwner-ом.

Шта је LiveData верзија 1.0 (увек актуелно)?

Карактеристика понашања: када LiveData добије новог активног Observer-а, он одмах добија последњу вредност (ако је постављена). Старе верзије LiveData-е (пре lifecycle 2.5.0) достављале су вредност чак и неактивним претплатницима при преласку у активно стање — ово је поправљено. У актуелној верзији LiveData добија последњу вредност при преласку ИЗ неактивног У активно стање, што поједностављује иницијализацију екрана.

Резиме

  • LiveData — посматрани контејнер података са аутоматским повезивањем на Lifecycle, елиминишући цурење меморије и крашове због застарелих референци.
  • MutableLiveData са setValue() (главна нит) и postValue() (позадинска нит) — главни API за промену података.
  • Трансформације map(), switchMap() и MediatorLiveData — функционални ланци без шаблонског кода.
  • liveData builder liveData { } — корутински приступ креирању асинхроних LiveData са аутоматским отказивањем корутина.
  • Room + LiveData — готова веза за локално кеширање без додатног кода у DAO.
  • LiveData се користи у 74% Jetpack пројеката и остаје стандард за Java код и legacy архитектуре.
  • За нове Kotlin пројекте Google препоручује StateFlow, али LiveData остаје компатибилно решење за хибридне стекове.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође