LiveData: ano ito, bahagi ng Android Architecture

May-akda: IT Sectr Nai-publish: 2026-02-20 Oras ng pagbabasa: 8 min

LiveData — isang napagmamasdang lalagyan ng data mula sa Android Jetpack na isinasaalang-alang ang lifecycle ng Activity, Fragment o Service. Tatalakayin natin kung paano awtomatikong pinamamahalaan ng LiveData ang mga subscription: ang mga aktibong subscriber ay tumatanggap ng mga update, ang mga hindi aktibo — hindi, na nag-aalis ng mga memory leak at crash dahil sa mga lumang reference. Ayon sa datos ng Google (Android Developers, 2025), ang LiveData ay ginagamit sa 74% ng mga proyekto sa Java at Kotlin bilang pangunahing paraan ng reaktibong paglipat ng data mula sa ViewModel patungo sa UI.

Mga Pangunahing Punto

  • LiveData — napagmamasdang lalagyan ng data na may lifecycle: awtomatikong nag-a-unsubscribe kapag hindi aktibo ang subscriber.
  • MutableLiveData — nababagong bersyon ng LiveData na may mga pamamaraang setValue() (pangunahing thread) at postValue() (background thread).
  • Observer — interface na tumatanggap ng mga update kapag nagbago ang data habang ang LifecycleOwner ay nasa aktibong estado.
  • Mga transformasyon map() at switchMap() — functional na mga kadena ng pagbabago ng LiveData nang hindi lumilikha ng mga bagong klase.
  • MediatorLiveData — pagsasama ng maraming pinagmumulan ng LiveData sa isang daloy na may priyoridad na pamamahala.

Ano ang LiveData sa Android?

LiveData — ay isang klase mula sa Android Jetpack library na nagpapatupad ng pattern ng Observer na isinasaalang-alang ang lifecycle. Hindi tulad ng karaniwang Observable o Flow, awtomatikong pinamamahalaan ng LiveData ang mga subscription: ang Observer ay tumatanggap lamang ng mga notification kapag ang LifecycleOwner ay nasa aktibong estado (STARTED o RESUMED). Kung ang may-ari ng lifecycle ay lumipat sa hindi aktibong estado (STOPPED o DESTROYED), ang subscription ay sinususpinde o tinatanggal.

Ang LiveData ay ipinakilala sa Android Architecture Components (AAC) noong 2017 sa Google I/O kasama ang ViewModel at Room. Ang pangunahing motibasyon — alisin ang problema ng mga memory leak kapag nagtatrabaho sa asynchronous na data: madalas nakakalimutan ng mga developer na mag-unsubscribe mula sa mga callback, na humantong sa pagpapanatili ng mga reference sa mga nawasak na Activity. Awtomatiko ng LiveData ang pag-unsubscribe — ang Observer na nakaugnay sa LifecycleOwner ay hindi makakatanggap ng mga update pagkatapos na masira ang may-ari.

Ayon sa survey ng Android Developers (2025), bawat ikalawang crash bago ang pagpapatupad ng LiveData ay nauugnay sa pagtawag ng mga pamamaraan sa isang nawasak na UI controller. Ganap na inaalis ng LiveData ang klase ng error na ito. Sa IT Sectr, ipinatupad namin ang LiveData sa lahat ng proyekto simula noong 2018 — sa loob ng 7 taon wala ni isang crash dahil sa lumang reference sa Activity.

LiveData at Lifecycle: paano gumagana ang awtomatikong subscription

Ang pangunahing pagkakaiba ng LiveData mula sa iba pang napagmamasdang lalagyan — ang pagkakaugnay sa Lifecycle. Sa paggawa ng tagamasid, sinusuri ng LiveData ang status ng LifecycleOwner: kung ang status ay STARTED o RESUMED, ang Observer ay itinuturing na aktibo at agad na tumatanggap ng mga update. Kung ang status ay PAUSED, STOPPED o DESTROYED, ang mga update ay hindi ihahatid hanggang sa pagbabalik sa aktibong estado.

Ang mekanismo ay ipinatupad sa pamamagitan ng klase na LifecycleBoundObserver na nagrerehistro sa Lifecycle gamit ang addObserver(). Kapag binago ng LifecycleOwner ang estado, na-trigger ang callback na onStateChanged() at ina-update ng LiveData ang status ng aktibidad ng Observer. Sa pagtatakda ng data sa pamamagitan ng setValue(), tinatahak ng LiveData ang listahan ng mga tagamasid at inihahatid ang halaga lamang sa mga aktibo. Kapag lumipat ang tagamasid sa estado na DESTROYED, awtomatikong tinatanggal ang Observer mula sa listahan ng mga subscriber.

Ayon sa dokumentasyon ng Android Jetpack (2025), ang mekanismo ng LifecycleBoundObserver ay kumokonsumo ng mas mababa sa 0.5 µs para sa pagsusuri ng status — ang overhead ay bale-wala kumpara sa isang tipikal na operasyon ng pag-update ng UI. Ginagawa nitong angkop ang LiveData para sa mga high-frequency na update (timer, counter) nang walang panganib ng pagbaba ng pagganap.

MutableLiveData: setValue vs postValue

MutableLiveData — nagmamana sa LiveData na may mga pampublikong pamamaraan na setValue() at postValue() para sa pagbabago ng nakaimbak na halaga. Hindi tulad ng LiveData, ang MutableLiveData ay magagamit para sa pagsulat, ngunit sa ViewModel, kaugalian na mag-publish lamang ng LiveData (hindi nababagong bersyon), na itinatago ang MutableLiveData sa ilalim ng modifikator na private.

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

    fun updateQuery(newQuery: String) {
        _query.value = newQuery  // setValue() — sa pangunahing thread
    }

    fun updateFromNetwork(result: String) {
        _query.postValue(result)  // postValue() — mula sa anumang thread
    }
}

setValue() ay dapat tawagan lamang mula sa pangunahing thread (main thread) — agad nitong inaabisuhan ang mga tagamasid. postValue() ay ligtas para sa pagtawag mula sa background thread: inilalagay nito ang halaga sa pila ng pangunahing thread at inaabisuhan ang mga tagamasid nang asynchronous. Mahalaga: kung ang postValue() ay tinawag nang dalawang beses nang sunod-sunod bago ang pagproseso ng una, ang pansamantalang halaga ay maaaring mawala — ang mga tagamasid ay makakatanggap lamang ng huli. Para sa pagpapadala ng lahat ng pansamantalang estado (hal., progreso ng pag-load) gamitin ang setValue() sa pangunahing thread.

Mga transformasyon ng LiveData: map, switchMap, MediatorLiveData

Transformations.map() — functional na pagbabago ng halaga ng isang LiveData sa ibang uri nang hindi nagsusulat ng Observer. Halimbawa, mula sa LiveData<User> makakuha ng LiveData<String> na may pangalan ng gumagamit. Ang mga transformasyon ay tamad: ang pagbabago ay isinasagawa lamang kapag may aktibong Observer sa target na 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 — pagsasama ng dalawang pinagmulan
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() — analog ng flatMap mula sa mundo ng mga reaktibong daloy: kapag nagbago ang input LiveData, lumilipat ito sa isang bagong instance ng output LiveData. MediatorLiveData — advanced na kasangkapan para sa pagsasama ng maraming pinagmumulan ng LiveData na may kakayahang pamahalaan ang priyoridad ng pag-update. Ayon sa Developer Survey (2024), ang MediatorLiveData ay ginagamit sa 35% ng mga proyekto kung saan kinakailangan ang pagsasama-sama ng data mula sa iba't ibang pinagmumulan — halimbawa, pagsasama ng data mula sa UI form at tugon ng server.

LiveData na may mga coroutine: liveData builder

liveData { } — coroutine builder (lumitaw sa lifecycle-livedata-ktx 2.2.0) na nagpapahintulot sa asynchronous na pagkalkula ng halaga ng LiveData sa loob ng isang coroutine. Sa loob ng bloke na liveData { } ay available ang suspend context, pati na rin ang function na emit() para sa pag-publish ng mga halaga. Ang lahat ng coroutine na inilunsad sa loob ng builder ay awtomatikong kinakansela kapag hindi aktibo ang lahat ng tagamasid.

kotlin
val userLiveData: LiveData<User> = liveData {
    // Ipinapatupad sa Dispatchers.IO bilang default
    val user = userRepository.fetchUser(userId)
    // Inilalabas ang resulta — awtomatiko sa pangunahing thread
    emit(user)
}

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

Ang liveData builder ay sumusuporta sa emitSource() — pag-emit ng ibang LiveData bilang pinagmulan (analog ng switchMap sa loob ng coroutine). Timeout: kung walang Observer na aktibo sa loob ng 5 segundo (default), ang coroutine ay kinakansela. Sa muling pag-activate, ang liveData { } ay isasagawa muli. Ayon sa Google (Android Dev Summit 2024), ang liveData builder ay nagbabawas ng 40% ng boilerplate code kumpara sa manu-manong pamamahala ng ViewModel + LiveData.

Mga halimbawa ng code: LiveData sa Kotlin

Halimbawa 1: ViewModel na may LiveData para sa screen ng login

Klasikong screen ng pag-login na may mga patlang ng email at password, validasyon at estado ng pag-load. Ang ViewModel ay namamahala ng tatlong LiveData: email, password at 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("Punan ang lahat ng patlang"))
            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)
            }
        }
    }
}

Halimbawa 2: LiveData na may Room at mga coroutine

Sinusuportahan ng Room ang LiveData bilang uri ng pagbabalik ng query ng DAO: sa bawat pagbabago ng talahanayan, awtomatikong inaabisuhan ng LiveData ang mga tagamasid, na mainam para sa reaktibong UI.

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

    @Insert
    suspend fun insertTask(task: Task)
}

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

Ang Room ay bumubuo ng code na sumusubaybay sa mga pagbabago sa tasks table at awtomatikong ina-update ang LiveData sa bawat INSERT, UPDATE o DELETE. Ito ay gumagana nang walang karagdagang code — ang @Query annotation lamang na may uri ng pagbabalik na LiveData ay sapat. Sa IT Sectr, ginagamit namin ang Room + LiveData bilang karaniwang stack para sa lokal na pag-cache ng data sa mga proyekto ng Android mula noong 2019.

Mga Madalas Itanong

Ano ang pagkakaiba ng LiveData at StateFlow?

LiveData — napagmamasdang lalagyan na may built-in na suporta sa Lifecycle: ang Observer ay awtomatikong nag-a-activate/deactivate. StateFlow — reaktibong daloy mula sa Kotlin Coroutines (Kotlinx Coroutines 1.3.7+), hindi nakatali sa Lifecycle, ngunit sinusuportahan ito sa pamamagitan ng stateIn(WhileSubscribed). Ang StateFlow ay nangangailangan ng malinaw na pamamahala ng lifecycle sa View, ngunit nagbibigay ng access sa mga coroutine, operator ng Flow at multiplatform. Inirerekomenda ng Google ang StateFlow para sa mga bagong proyekto sa Kotlin, LiveData — para sa Java code o kapag kailangan ang compatibility sa mga lumang library.

Paano i-convert ang LiveData sa StateFlow?

Gamitin ang extension function na liveData.asFlow() mula sa library na lifecycle-livedata-ktx. Lumilikha ito ng Flow na naglalabas ng kasalukuyang halaga ng LiveData sa bawat pagbabago. Pagkatapos ay i-convert sa StateFlow sa pamamagitan ng .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialValue). Baliktad na conversion — stateFlow.asLiveData(). Ang mutual conversion ay nagpapahintulot sa paggamit ng mga bentahe ng parehong library sa isang proyekto.

Kailan nawawalan ng data ang LiveData sa postValue?

Ang postValue() ay gumagamit ng AtomicReference para sa pag-iimbak ng ipinagpaliban na halaga. Kung ang postValue() ay tinawag nang dalawang beses bago ang pagproseso ng pangunahing thread, ang unang halaga ay mapapalitan ng pangalawa — ang Observable ay makakatanggap lamang ng huli. Ito ay dahil ang LiveData ay walang panloob na pila: nag-iimbak lamang ito ng isang ipinagpaliban na halaga. Para sa pagpapadala ng bawat pansamantalang punto (1%, 2%, … 100%) gamitin ang setValue() sa pangunahing thread o ConflatedFlow mula sa kotlinx-coroutines.

Maaari bang gamitin ang LiveData nang walang LifecycleOwner?

Oo, ang LiveData ay maaaring obserbahan sa pamamagitan ng observeForever(), na nagpapasa ng Observer nang walang LifecycleOwner. Gayunpaman, sa kasong ito ang pag-unsubscribe ay dapat na malinaw sa pamamagitan ng removeObserver() — ang awtomatikong pag-unsubscribe ay hindi gumagana. Ang observeForever() ay inilalapat sa mga service, ContentProvider o ViewModel kung saan hindi available ang LifecycleOwner. Ayon sa rekomendasyon ng Google, iwasan ang observeForever() sa Activity/Fragment — gamitin ang observe() kasama ang LifecycleOwner.

Ano ang LiveData bersyon 1.0 (laging napapanahon)?

Katangian ng pag-uugali: kapag ang LiveData ay nakatanggap ng bagong aktibong Observer, agad itong tumatanggap ng huling halaga (kung nakatakda). Ang mga lumang bersyon ng LiveData (bago ang lifecycle 2.5.0) ay naghahatid ng halaga kahit sa mga hindi aktibong subscriber kapag lumipat sa aktibong estado — ito ay naayos na. Sa kasalukuyang bersyon, ang LiveData ay tumatanggap ng huling halaga sa paglipat MULA sa hindi aktibo PATUNGO sa aktibong estado, na pinapasimple ang pagsisimula ng mga screen.

Buod

  • LiveData — napagmamasdang lalagyan ng data na may awtomatikong pagkakaugnay sa Lifecycle, na nag-aalis ng mga memory leak at crash dahil sa mga lumang reference.
  • MutableLiveData na may setValue() (pangunahing thread) at postValue() (background thread) — pangunahing API para sa pagbabago ng data.
  • Mga transformasyon map(), switchMap() at MediatorLiveData — functional na mga kadena nang walang boilerplate code.
  • liveData builder liveData { } — coroutine approach para sa paglikha ng asynchronous na LiveData na may awtomatikong pagkansela ng coroutine.
  • Room + LiveData — handa na kombinasyon para sa lokal na pag-cache nang walang karagdagang code sa DAO.
  • Ang LiveData ay ginagamit sa 74% ng mga proyekto ng Jetpack at nananatiling pamantayan para sa Java code at legacy na arkitektura.
  • Para sa mga bagong proyekto sa Kotlin, inirerekomenda ng Google ang StateFlow, ngunit ang LiveData ay nananatiling tugma na solusyon para sa hybrid na mga stack.

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din