LiveData — Android Jetpack-dən Activity, Fragment və ya Service-in həyat dövrünü nəzərə alan müşahidə edilən məlumat konteyneri. LiveData-nın abunəlikləri avtomatik idarə etməsini izah edəcəyik: aktiv abunəçilər yeniləmələri alır, qeyri-aktivlər isə almır, bu da yaddaş sızmalarını və köhnəlmiş istinadlar səbəbindən crash-ləri aradan qaldırır. Google məlumatlarına görə (Android Developers, 2025), LiveData Java və Kotlin layihələrinin 74%-də ViewModel-dən UI-ə reaktiv məlumat ötürmənin əsas üsulu kimi istifadə olunur.
Əsas məqamlar
LiveData — Android Jetpack kitabxanasından həyat dövrünü nəzərə alan Observer nümunəsini həyata keçirən sinifdir. Standart Observable və ya Flow-dan fərqli olaraq, LiveData abunəlikləri avtomatik idarə edir: Observer yalnız LifecycleOwner aktiv vəziyyətdə olduqda (STARTED və ya RESUMED) bildirişlər alır. Həyat dövrü sahibi qeyri-aktiv vəziyyətə (STOPPED və ya DESTROYED) keçərsə, abunəlik dayandırılır və ya silinir.
LiveData Android Architecture Components (AAC) çərçivəsində 2017-ci ildə Google I/O konfransında ViewModel və Room ilə birlikdə təqdim edilmişdir. Əsas məqsəd asinxron məlumatlarla işləyərkən yaddaş sızmaları problemini aradan qaldırmaq idi: tərtibatçılar tez-tez callback-lərdən çıxmağı unudurdular, bu da məhv edilmiş Activity-lərə istinadların saxlanmasına səbəb olurdu. LiveData çıxmağı avtomatlaşdırır — LifecycleOwner ilə əlaqəli Observer sahib məhv edildikdən sonra yeniləmələri almır.
Android Developers (2025) sorğusuna görə, LiveData tətbiq edilməzdən əvvəl hər ikinci crash məhv edilmiş UI kontrollerində metodların çağırılması ilə əlaqəli idi. LiveData bu səhv sinfini tamamilə aradan qaldırır. IT Sectr olaraq biz LiveData-nı 2018-ci ildən bütün layihələrimizə tətbiq etdik — 7 il ərzində Activity-yə köhnəlmiş istinad səbəbindən bir dənə də olsun crash baş vermədi.
LiveData-nın digər müşahidə konteynerlərindən əsas fərqi — Lifecycle ilə əlaqələndirilməsidir. Müşahidəçi yaradılarkən LiveData LifecycleOwner statusunu yoxlayır: status STARTED və ya RESUMED olarsa, Observer aktiv sayılır və dərhal yeniləmələri alır. Status PAUSED, STOPPED və ya DESTROYED olarsa, yeniləmələr aktiv vəziyyətə qayıdana qədər çatdırılmır.
Mexanizm LifecycleBoundObserver sinfi vasitəsilə həyata keçirilir, o addObserver() ilə Lifecycle-də qeydiyyatdan keçir. LifecycleOwner vəziyyət dəyişdikdə onStateChanged() callback-i işə düşür və LiveData Observer-in aktivlik statusunu yeniləyir. setValue() vasitəsilə məlumat təyin edilərkən LiveData müşahidəçilər siyahısını keçir və dəyəri yalnız aktiv olanlara çatdırır. Müşahidəçi DESTROYED vəziyyətinə keçdikdə Observer avtomatik olaraq abunəçilər siyahısından silinir.
Android Jetpack sənədlərinə görə (2025), LifecycleBoundObserver mexanizmi status yoxlamasına 0,5 µs-dən az sərf edir — bu, tipik UI yeniləmə əməliyyatı ilə müqayisədə əhəmiyyətsiz dərəcədə kiçikdir. Bu, LiveData-nı performans itkisi riski olmadan yüksək tezlikli yeniləmələr (taymerlər, sayğaclar) üçün uyğun edir.
MutableLiveData — saxlanılan dəyəri dəyişmək üçün açıq setValue() və postValue() metodları olan LiveData varisidir. LiveData-dan fərqli olaraq, MutableLiveData yazmaq üçün əlçatandır, lakin ViewModel-də yalnız LiveData-nı (dəyişməz versiya) dərc etmək, MutableLiveData-nı isə private modifikatoru altında gizlətmək adətdir.
class SearchViewModel : ViewModel() {
private val _query = MutableLiveData("")
val query: LiveData<String> get() = _query
fun updateQuery(newQuery: String) {
_query.value = newQuery // setValue() — əsas thread-də
}
fun updateFromNetwork(result: String) {
_query.postValue(result) // postValue() — istənilən thread-dən
}
}
setValue() yalnız əsas thread-dən çağırılmalıdır — o dərhal müşahidəçilərə bildiriş göndərir. postValue() fon thread-dən çağırış üçün təhlükəsizdir: dəyəri əsas thread-in növbəsinə yerləşdirir və müşahidəçilərə asinxron bildiriş göndərir. Vacib: əgər postValue() birincinin işlənməsindən əvvəl iki dəfə çağırılırsa, aralıq dəyər itirilə bilər — müşahidəçilər yalnız sonuncunu alacaq. Bütün aralıq vəziyyətləri ötürmək üçün (məsələn, yükləmə gedişatı) əsas thread-də setValue() istifadə edin.
Transformations.map() — Observer yazmadan bir LiveData dəyərini başqa tipə funksional çevirmə. Məsələn, LiveData<User>-dən istifadəçi adı ilə LiveData<String> əldə etmək. Transformasiyalar tənbəldir: çevirmə yalnız hədəf LiveData-da aktiv Observer olduqda icra olunur.
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 mənbəyin birləşdirilməsi
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() — reaktiv axınlar dünyasından flatMap-in analoqu: giriş LiveData dəyişdikdə çıxış LiveData-nın yeni nümunəsinə keçir. MediatorLiveData — yeniləmə prioritetini idarə etmək imkanı ilə bir neçə LiveData mənbəyini birləşdirmək üçün qabaqcıl alət. Developer Survey (2024) məlumatına görə, MediatorLiveData müxtəlif mənbələrdən məlumat aqreqasiyası tələb edən layihələrin 35%-də istifadə olunur — məsələn, UI forma məlumatları və server cavabının birləşdirilməsi.
liveData { } — korutina daxilində LiveData dəyərini asinxron hesablamağa imkan verən coroutine builder (lifecycle-livedata-ktx 2.2.0-da təqdim edilmişdir). liveData { } bloku daxilində suspend konteksti, həmçinin dəyərləri dərc etmək üçün emit() funksiyası mövcuddur. Builder daxilində işə salınmış bütün korutinlar bütün müşahidəçilər qeyri-aktiv olduqda avtomatik ləğv edilir.
val userLiveData: LiveData<User> = liveData {
// Dispatchers.IO-da standart olaraq icra olunur
val user = userRepository.fetchUser(userId)
// Nəticəni emit edirik — avtomatik əsas thread-də
emit(user)
}
val progressLiveData: LiveData<Int> = liveData {
for (i in 0..100) {
emit(i)
delay(50)
}
}
liveData builder emitSource() funksiyasını dəstəkləyir — başqa LiveData-nın mənbə kimi emit edilməsi (korutina daxilində switchMap analoqu). Timeout: heç bir Observer 5 saniyə (standart) aktiv olmazsa, korutina ləğv edilir. Yenidən aktivləşdirmədə liveData { } əvvəldən icra olunur. Google məlumatına görə (Android Dev Summit 2024), liveData builder əl ilə ViewModel + LiveData idarəsi ilə müqayisədə 40% şablon kodu azaldır.
Email və şifrə sahələri, validasiya və yükləmə vəziyyəti olan klassik giriş ekranı. ViewModel üç LiveData idarə edir: email, password və 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("Bütün sahələri 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 LiveData-nı DAO sorğusunun qaytarılan tipi kimi dəstəkləyir: cədvəl hər dəfə dəyişdikdə LiveData avtomatik müşahidəçilərə bildiriş göndərir, bu da reaktiv UI üçün idealdır.
@Dao
interface TaskDao {
@Query("SELECT * FROM tasks WHERE completed = 0")
fun getActiveTasks(): LiveData<List<Task>>
@Insert
suspend fun insertTask(task: Task)
}
// ViewModel-də:
class TaskViewModel(application: Application) : AndroidViewModel(application) {
private val dao = AppDatabase.getDatabase(application).taskDao()
val activeTasks: LiveData<List<Task>> = dao.getActiveTasks()
}
Room tasks cədvəlindəki dəyişiklikləri izləyən kod yaradır və hər INSERT, UPDATE və ya DELETE zamanı LiveData-nı avtomatik yeniləyir. Bu əlavə kod olmadan işləyir — yalnız LiveData qaytarılan tipi ilə @Query annotasiyası kifayətdir. IT Sectr olaraq biz 2019-cu ildən Android layihələrində lokalkeşdə məlumat saxlama üçün Room + LiveData standart yığınından istifadə edirik.
Tez-tez verilən suallar
LiveData — daxili Lifecycle dəstəyi olan müşahidə konteyneri: Observer avtomatik aktivləşir/deaktivləşir. StateFlow — Kotlin Coroutines-dən (Kotlinx Coroutines 1.3.7+) reaktiv axın, Lifecycle-ə bağlı deyil, lakin stateIn(WhileSubscribed) vasitəsilə bunu dəstəkləyir. StateFlow View-də həyat dövrünün açıq idarə edilməsini tələb edir, lakin korutinlərə, Flow operatorlarına və çoxplatformalılığa çıxış verir. Google yeni Kotlin layihələri üçün StateFlow-u, Java kodu və ya köhnə kitabxanalarla uyğunluq üçün LiveData-nı tövsiyə edir.
lifecycle-livedata-ktx kitabxanasından liveData.asFlow() genişləndirmə funksiyasından istifadə edin. O, hər dəyişiklikdə LiveData-nın cari dəyərini emit edən Flow yaradır. Sonra .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialValue) ilə StateFlow-a çevirin. Əks çevirmə — stateFlow.asLiveData(). Qarşılıqlı konvertasiya bir layihədə hər iki kitabxananın üstünlüklərindən istifadə etməyə imkan verir.
postValue() təxirə salınmış dəyəri saxlamaq üçün AtomicReference istifadə edir. Əgər postValue() əsas thread tərəfindən işlənmədən əvvəl iki dəfə çağırılırsa, birinci dəyər ikinci ilə üzərinə yazılacaq — Observable yalnız sonuncunu alacaq. Bu, LiveData-nın daxili növbəsinin olmaması ilə bağlıdır: o yalnız bir təxirə salınmış dəyər saxlayır. Hər aralıq nöqtəni (1%, 2%, … 100%) ötürmək üçün əsas thread-də setValue() və ya kotlinx-coroutines-dən ConflatedFlow istifadə edin.
Bəli, LiveData-nı observeForever() vasitəsilə müşahidə etmək olar, Observer-i LifecycleOwner olmadan ötürməklə. Lakin bu halda abunəlikdən çıxma removeObserver() ilə açıq şəkildə aparılmalıdır — avtomatik çıxma işləmir. observeForever() LifecycleOwner-in mövcud olmadığı servislərdə, ContentProvider-də və ya ViewModel-də tətbiq olunur. Google tövsiyəsinə əsasən, Activity/Fragment-də observeForever()-dən çəkinin — LifecycleOwner ilə observe() istifadə edin.
Davranış xüsusiyyəti: LiveData yeni aktiv Observer aldıqda dərhal son dəyəri alır (əgər təyin edilibsə). LiveData-nın köhnə versiyaları (lifecycle 2.5.0-dan əvvəl) aktiv vəziyyətə keçərkən hətta qeyri-aktiv abunəçilərə də dəyər çatdırırdı — bu düzəldilib. Cari versiyada LiveData son dəyəri qeyri-aktivdən aktiv vəziyyətə KEÇİD zamanı alır, bu da ekranların inisializasiyasını sadələşdirir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun