LiveData — observerbar databehållare från Android Jetpack som tar hänsyn till livscykeln för Activity, Fragment eller Service. Låt oss se hur LiveData automatiskt hanterar prenumerationer: aktiva prenumeranter får uppdateringar, inaktiva — inte, vilket eliminerar minnesläckor och krascher på grund av föråldrade referenser. Enligt Google (Android Developers, 2025) används LiveData i 74% av projekt på Java och Kotlin som det främsta sättet för reaktiv dataöverföring från ViewModel till UI.
Huvudpunkter
LiveData — är en klass från Android Jetpack-biblioteket som implementerar Observer-mönstret med hänsyn till livscykeln. Till skillnad från standard Observable eller Flow hanterar LiveData automatiskt prenumerationer: Observer får meddelanden endast när LifecycleOwner är i aktivt tillstånd (STARTED eller RESUMED). Om livscykelägaren går över till inaktivt tillstånd (STOPPED eller DESTROYED) pausas eller tas prenumerationen bort.
LiveData introducerades i Android Architecture Components (AAC) 2017 på Google I/O tillsammans med ViewModel och Room. Huvudmotivationen var att eliminera problemet med minnesläckor vid arbete med asynkron data: utvecklare glömde ofta att avsluta prenumerationer på callbacks, vilket ledde till att referenser till förstörda Activity behölls. LiveData gör avprenumeration automatisk — Observer kopplad till LifecycleOwner får inga uppdateringar efter att ägaren förstörts.
Enligt Android Developers undersökning (2025) var varannan krasch före införandet av LiveData relaterad till anrop av metoder på en förstörd UI-kontroller. LiveData eliminerar helt denna typ av fel. På IT Sectr implementerade vi LiveData i alla projekt från och med 2018 — på 7 år inte en enda krasch på grund av föråldrad referens till Activity.
Den viktigaste skillnaden med LiveData från andra observerbara behållare — bindning till Lifecycle. När en observatör skapas kontrollerar LiveData LifecycleOwners status: om statusen är STARTED eller RESUMED anses Observer vara aktiv och får uppdateringar omedelbart. Om statusen är PAUSED, STOPPED eller DESTROYED levereras inga uppdateringar förrän återgång till aktivt tillstånd.
Mekanismen implementeras genom klassen LifecycleBoundObserver, som registreras i Lifecycle med addObserver(). När LifecycleOwner ändrar tillstånd aktiveras callback onStateChanged() och LiveData uppdaterar Observers aktivitetsstatus. Vid inställning av data via setValue() går LiveData igenom listan över observatörer och levererar värdet endast till aktiva. När observatören går till tillståndet DESTROYED tas Observer automatiskt bort från prenumerantlistan.
Enligt Android Jetpack-dokumentationen (2025) förbrukar LifecycleBoundObserver-mekanismen mindre än 0,5 μs per statuskontroll — omkostnaderna är försumbara jämfört med en typisk UI-uppdateringsoperation. Detta gör LiveData lämplig för högfrekventa uppdateringar (timer, räknare) utan risk för prestandaförsämring.
MutableLiveData — arvtagare till LiveData med öppna metoder setValue() och postValue() för att ändra det lagrade värdet. Till skillnad från LiveData är MutableLiveData skrivbart, men i ViewModel är det praxis att bara publicera LiveData (oföränderlig version) och dölja MutableLiveData under modifieraren private.
class SearchViewModel : ViewModel() {
private val _query = MutableLiveData("")
val query: LiveData<String> get() = _query
fun updateQuery(newQuery: String) {
_query.value = newQuery // setValue() — på main thread
}
fun updateFromNetwork(result: String) {
_query.postValue(result) // postValue() — från valfri tråd
}
}
setValue() får endast anropas från huvudtråden (main thread) — den meddelar omedelbart observatörerna. postValue() är säker att anropa från en bakgrundstråd: den placerar värdet i huvudtrådens kö och meddelar observatörerna asynkront. Viktigt: om postValue() anropas två gånger i rad innan den första bearbetas kan det mellanliggande värdet gå förlorat — observatörerna får bara det sista värdet. För att överföra alla mellanliggande tillstånd (t.ex. laddningsförlopp) använd setValue() på huvudtråden.
Transformations.map() — funktionell omvandling av ett LiveData-värde till en annan typ utan att skriva Observer. Till exempel från LiveData<User> få LiveData<String> med användarnamnet. Transformationer är lata: omvandlingen utförs endast när det finns en aktiv Observer på mål-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 — sammanslagning av två källor
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() — motsvarighet till flatMap från reaktiva strömmar: när indata-LiveData ändras växlar den till en ny instans av utdata-LiveData. MediatorLiveData — avancerat verktyg för att slå samman flera LiveData-källor med möjlighet att styra uppdateringsprioritet. Enligt Developer Survey (2024) används MediatorLiveData i 35% av projekt där aggregering av data från olika källor krävs — till exempel sammanslagning av data från UI-formulär och serversvar.
liveData { } — coroutine builder (introducerad i lifecycle-livedata-ktx 2.2.0) som möjliggör asynkron beräkning av LiveData-värde inuti en korutin. Inuti blocket liveData { } finns suspend-kontext samt funktionen emit() för publicering av värden. Alla korutiner som startas inuti builder avbryts automatiskt när alla observatörer är inaktiva.
val userLiveData: LiveData<User> = liveData {
// Utförs på Dispatchers.IO som standard
val user = userRepository.fetchUser(userId)
// Emittera resultatet — automatiskt på main thread
emit(user)
}
val progressLiveData: LiveData<Int> = liveData {
for (i in 0..100) {
emit(i)
delay(50)
}
}
liveData builder stöder emitSource() — emission av en annan LiveData som källa (motsvarighet till switchMap inuti korutin). Timeout: om ingen Observer är aktiv inom 5 sekunder (standard) avbryts korutinen. Vid återaktivering körs liveData { } på nytt. Enligt Google (Android Dev Summit 2024) minskar liveData builder 40% av standardkoden jämfört med manuell hantering av ViewModel + LiveData.
Klassisk inloggningsskärm med fälten e-post och lösenord, validering och laddningstillstånd. ViewModel hanterar tre LiveData: email, password och 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("Fyll i alla fält"))
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 stöder LiveData som returtyp för DAO-fråga: vid varje tabelländring meddelar LiveData automatiskt observatörerna, vilket är idealiskt för reactice UI.
@Dao
interface TaskDao {
@Query("SELECT * FROM tasks WHERE completed = 0")
fun getActiveTasks(): LiveData<List<Task>>
@Insert
suspend fun insertTask(task: Task)
}
// I ViewModel:
class TaskViewModel(application: Application) : AndroidViewModel(application) {
private val dao = AppDatabase.getDatabase(application).taskDao()
val activeTasks: LiveData<List<Task>> = dao.getActiveTasks()
}
Room genererar kod som spårar ändringar i tabellen tasks och automatiskt uppdaterar LiveData vid INSERT, UPDATE eller DELETE. Detta fungerar utan extra kod — endast @Query-annotering med returtypen LiveData. På IT Sectr använder vi Room + LiveData som standardstack för lokal datacache i Android-projekt sedan 2019.
Vanliga frågor
LiveData — observerbar behållare med inbyggt Lifecycle-stöd: Observer aktiveras/avaktiveras automatiskt. StateFlow — reaktiv ström från Kotlin Coroutines (Kotlinx Coroutines 1.3.7+), inte bunden till Lifecycle men stöder det via stateIn(WhileSubscribed). StateFlow kräver explicit livscykelhantering i View men ger tillgång till korutiner, Flow-operatorer och multiplattform. Google rekommenderar StateFlow för nya projekt i Kotlin, LiveData — för Java-kod eller vid behov av kompatibilitet med gamla bibliotek.
Använd extension-funktionen liveData.asFlow() från biblioteket lifecycle-livedata-ktx. Den skapar en Flow som emitterar aktuellt LiveData-värde vid varje ändring. Konvertera sedan till StateFlow via .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialValue). Omvänd konvertering — stateFlow.asLiveData(). Ömsesidig konvertering gör det möjligt att använda fördelarna med båda biblioteken i ett projekt.
postValue() använder AtomicReference för att lagra uppskjutet värde. Om postValue() anropas två gånger innan huvudtråden hinner bearbeta kommer det första värdet att skrivas över av det andra — Observable får bara det sista. Detta beror på att LiveData inte har någon intern kö: det lagrar bara ett uppskjutet värde. För att överföra varje mellanliggande punkt (1%, 2%, … 100%) använd setValue() på huvudtråden eller ConflatedFlow från kotlinx-coroutines.
Ja, LiveData kan observeras via observeForever() genom att skicka Observer utan LifecycleOwner. I detta fall måste avprenumeration vara explicit via removeObserver() — automatisk avprenumeration fungerar inte. observeForever() används i tjänster, ContentProvider eller ViewModel där LifecycleOwner inte är tillgänglig. Enligt Googles rekommendation, undvik observeForever() i Activity/Fragment — använd observe() med LifecycleOwner.
Beteendeegenskap: när LiveData får en ny aktiv Observer får den omedelbart det senaste värdet (om det är satt). Gamla versioner av LiveData (före lifecycle 2.5.0) levererade värdet även till inaktiva prenumeranter vid övergång till aktivt tillstånd — detta är åtgärdat. I aktuell version får LiveData det senaste värdet vid övergång FRÅN inaktivt TILL aktivt tillstånd, vilket förenklar initiering av skärmar.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också