LiveData, Android Jetpack'ten Activity, Fragment veya Service'in yaşam döngüsünü dikkate alan gözlemlenebilir bir veri kapsayıcısıdır. LiveData'nın abonelikleri nasıl otomatik olarak yönettiğini keşfedelim: aktif aboneler güncellemeleri alır, pasif olanlar almaz, bu da eski referanslar nedeniyle bellek sızıntılarını ve çökmeleri ortadan kaldırır. Google'a (Android Developers, 2025) göre LiveData, Java ve Kotlin projelerinin %74'ünde ViewModel'den UI'ya reaktif veri aktarımının ana yolu olarak kullanılır.
Önemli Noktalar
LiveData, Android Jetpack kütüphanesinden, yaşam döngüsü farkındalığına sahip Observer desenini uygulayan bir sınıftır. Standart Observable veya Flow'un aksine, LiveData abonelikleri otomatik olarak yönetir: bir Observer, yalnızca LifecycleOwner aktif durumdayken (STARTED veya RESUMED) bildirim alır. Yaşam döngüsü sahibi pasif bir duruma (STOPPED veya DESTROYED) geçerse, abonelik duraklatılır veya kaldırılır.
LiveData, 2017'de Google I/O'da ViewModel ve Room ile birlikte Android Architecture Components (AAC)'de tanıtıldı. Ana motivasyon, asenkron verilerle çalışırken bellek sızıntılarını ortadan kaldırmaktı: geliştiriciler genellikle geri aramalardan abonelikten çıkmayı unutuyordu, bu da yok edilmiş Activity'lere referansların tutulmasına yol açıyordu. LiveData, abonelikten çıkmayı otomatik hale getirir — bir LifecycleOwner ile ilişkilendirilmiş Observer, sahip yok edildikten sonra güncelleme almaz.
Android Developers anketine (2025) göre, LiveData benimsenmeden önce her iki çökmeden biri, yok edilmiş bir UI denetleyicisinde metot çağrılmasıyla ilgiliydi. LiveData bu hata sınıfını tamamen ortadan kaldırır. IT Sectr'da, 2018'den beri tüm projelerde LiveData'yı uyguladık — 7 yılı aşkın süredir eski Activity referansları nedeniyle sıfır çökme.
LiveData'nın temel farkı, diğer gözlemlenebilir kapsayıcılardan Lifecycle'a bağlı olmasıdır. Bir gözlemci oluşturulduğunda, LiveData LifecycleOwner'ın durumunu kontrol eder: durum STARTED veya RESUMED ise, Observer aktif kabul edilir ve güncellemeleri hemen alır. Durum PAUSED, STOPPED veya DESTROYED ise, aktif duruma dönene kadar güncellemeler iletilmez.
Mekanizma, addObserver() kullanarak Lifecycle'a kaydolan LifecycleBoundObserver sınıfı aracılığıyla uygulanır. LifecycleOwner durum değiştirdiğinde, onStateChanged() geri çağırması tetiklenir ve LiveData, Observer'ın etkinlik durumunu günceller. Veriler setValue() ile ayarlandığında, LiveData gözlemci listesini dolaşır ve değeri yalnızca aktif olanlara iletir. Bir gözlemci DESTROYED durumuna geçtiğinde, Observer otomatik olarak abone listesinden kaldırılır.
Android Jetpack belgelerine (2025) göre, LifecycleBoundObserver mekanizması durum kontrolü başına 0,5 µs'den az tüketir — tipik bir UI güncelleme işlemine kıyasla ek yük ihmal edilebilir düzeydedir. Bu, LiveData'yı performans düşüşü riski olmadan yüksek frekanslı güncellemeler (zamanlayıcılar, sayaçlar) için uygun hale getirir.
MutableLiveData, depolanan değeri değiştirmek için genel setValue() ve postValue() metotlarına sahip LiveData'nın bir alt sınıfıdır. LiveData'nın aksine, MutableLiveData yazılabilir, ancak ViewModel'de yalnızca LiveData'yı (değişmez sürüm) açığa çıkarmak ve MutableLiveData'yı private değiştiricisinin arkasında gizlemek yaygın bir uygulamadır.
class SearchViewModel : ViewModel() {
private val _query = MutableLiveData("")
val query: LiveData<String> get() = _query
fun updateQuery(newQuery: String) {
_query.value = newQuery // setValue() — ana iş parçacığında
}
fun updateFromNetwork(result: String) {
_query.postValue(result) // postValue() — herhangi bir iş parçacığından
}
}
setValue() yalnızca ana iş parçacığından çağrılmalıdır — gözlemcileri hemen bilgilendirir. postValue(), arka plan iş parçacığından çağırmak için güvenlidir: değeri ana iş parçacığının kuyruğuna koyar ve gözlemcileri asenkron olarak bilgilendirir. Önemli: postValue(), ilki işlenmeden önce arka arkaya iki kez çağrılırsa, ara değer kaybolabilir — gözlemcilere yalnızca son değer ulaşır. Tüm ara durumları (örneğin, yükleme ilerlemesi) iletmek için ana iş parçacığında setValue() kullanın.
Transformations.map() — Observer yazmadan bir LiveData değerinin başka bir türe işlevsel dönüşümü. Örneğin, LiveData<User>'dan kullanıcı adıyla LiveData<String> almak. Dönüşümler tembeldir: dönüşüm yalnızca hedef LiveData'da aktif bir Observer olduğunda gerçekleştirilir.
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 — iki kaynağın birleştirilmesi
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() — reaktif akışlar dünyasından flatMap'in bir benzeri: girdi LiveData değiştiğinde, çıktı LiveData'nın yeni bir örneğine geçer. MediatorLiveData — güncelleme önceliğini yönetme yeteneği ile birden çok LiveData kaynağını birleştirmek için gelişmiş bir araçtır. Developer Survey (2024)'e göre MediatorLiveData, farklı kaynaklardan veri toplama gerektiren projelerin %35'inde kullanılır — örneğin, UI form verileri ve sunucu yanıtını birleştirme.
liveData { } — bir coroutine oluşturucudur (lifecycle-livedata-ktx 2.2.0'da tanıtıldı) ve bir coroutine içinde LiveData değerlerinin asenkron olarak hesaplanmasına olanak tanır. liveData { } bloğu içinde, bir suspend bağlamı ve değerleri yayınlamak için emit() işlevi bulunur. Oluşturucu içinde başlatılan tüm coroutine'ler, tüm gözlemciler pasif hale geldiğinde otomatik olarak iptal edilir.
val userLiveData: LiveData<User> = liveData {
// Varsayılan olarak Dispatchers.IO'da yürütülür
val user = userRepository.fetchUser(userId)
// Sonuç yayınlanıyor — otomatik olarak ana iş parçacığında
emit(user)
}
val progressLiveData: LiveData<Int> = liveData {
for (i in 0..100) {
emit(i)
delay(50)
}
}
liveData builder, emitSource()'ı destekler — kaynak olarak başka bir LiveData yayını (bir coroutine içindeki switchMap'e benzer). Zaman aşımı: 5 saniye (varsayılan) boyunca hiçbir Observer aktif değilse, coroutine iptal edilir. Yeniden etkinleştirildiğinde, liveData { } yeniden çalıştırılır. Google'a (Android Dev Summit 2024) göre liveData builder, manuel ViewModel + LiveData yönetimine kıyasla kalıplaşmış kodu %40 azaltır.
E-posta ve şifre alanları, doğrulama ve yükleme durumu içeren klasik bir giriş ekranı. ViewModel üç LiveData'yı yönetir: email, password ve 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("Tüm alanları doldurun"))
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, DAO sorguları için dönüş türü olarak LiveData'yı destekler: tablo her değiştiğinde LiveData otomatik olarak gözlemcileri bilgilendirir, bu da reaktif UI için idealdir.
@Dao
interface TaskDao {
@Query("SELECT * FROM tasks WHERE completed = 0")
fun getActiveTasks(): LiveData<List<Task>>
@Insert
suspend fun insertTask(task: Task)
}
// ViewModel'de:
class TaskViewModel(application: Application) : AndroidViewModel(application) {
private val dao = AppDatabase.getDatabase(application).taskDao()
val activeTasks: LiveData<List<Task>> = dao.getActiveTasks()
}
Room, tasks tablosundaki değişiklikleri izleyen ve her INSERT, UPDATE veya DELETE'te LiveData'yı otomatik olarak güncelleyen kod oluşturur. Bu ek kod olmadan çalışır — yalnızca LiveData dönüş türüyle @Query ek açıklaması yeterlidir. IT Sectr'da, 2019'dan beri Android projelerinde yerel veri önbellekleme için standart yığın olarak Room + LiveData kullanıyoruz.
Sıkça Sorulan Sorular
LiveData, yerleşik Lifecycle desteğine sahip gözlemlenebilir bir kapsayıcıdır: Observer otomatik olarak etkinleştirilir/devre dışı bırakılır. StateFlow, Kotlin Coroutines'den (Kotlinx Coroutines 1.3.7+) reaktif bir akıştır, Lifecycle'a bağlı değildir ancak stateIn(WhileSubscribed) aracılığıyla bunu destekler. StateFlow, View'da açık yaşam döngüsü yönetimi gerektirir, ancak coroutine'lere, Flow operatörlerine ve çoklu platform yeteneklerine erişim sağlar. Google, yeni Kotlin projeleri için StateFlow'u, Java kodu veya eski kütüphanelerle uyumluluk gerektiğinde LiveData'yı önerir.
lifecycle-livedata-ktx kütüphanesinden liveData.asFlow() uzantı işlevini kullanın. Her değişiklikte geçerli LiveData değerini yayan bir Flow oluşturur. Ardından .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialValue) ile StateFlow'a dönüştürün. Ters dönüşüm stateFlow.asLiveData()'dır. Karşılıklı dönüşüm, tek bir projede her iki kütüphanenin avantajlarından yararlanmayı sağlar.
postValue(), bekleyen değeri depolamak için AtomicReference kullanır. Ana iş parçacığı işlemeden önce postValue() iki kez çağrılırsa, ilk değer ikinci tarafından üzerine yazılır — Observer yalnızca son değeri alır. Bunun nedeni LiveData'nın dahili bir kuyruğunun olmamasıdır: yalnızca bir bekleyen değer depolar. Her ara noktayı (%1, %2, … %100) iletmek için ana iş parçacığında setValue() veya kotlinx-coroutines'den ConflatedFlow kullanın.
Evet, LiveData, LifecycleOwner olmadan bir Observer geçirerek observeForever() aracılığıyla gözlemlenebilir. Ancak bu durumda abonelikten çıkma, removeObserver() aracılığıyla açık olmalıdır — otomatik abonelikten çıkma çalışmaz. observeForever(), LifecycleOwner'ın bulunmadığı servislerde, ContentProvider'da veya ViewModel'de kullanılır. Google'ın önerisine göre, Activity/Fragment'te observeForever()'dan kaçının — LifecycleOwner ile observe() kullanın.
Davranış özelliği: LiveData yeni bir aktif Observer aldığında, hemen en son değeri (ayarlanmışsa) alır. LiveData'nın eski sürümleri (lifecycle 2.5.0 öncesi), aktif duruma geçerken pasif abonelere bile değer iletiyordu — bu düzeltildi. Mevcut sürümde LiveData, pasiften aktife geçerken en son değeri iletir, bu da ekran başlatmayı basitleştirir.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun