LiveData — Android Jetpack-dan Activity, Fragment yoki Service hayotiy sikliga moslashadigan kuzatiladigan ma'lumot konteyneri. LiveData obunalarni qanday avtomatik boshqarishini tahlil qilamiz: faol obunachilar yangilanishlarni oladi, nofaollari esa olmaydi, bu xotira oqishlarini va eskirgan havolalar tufayli crash-larni bartaraf qiladi. Google ma'lumotlariga ko'ra (Android Developers, 2025), LiveData 74% Java va Kotlin loyihalarida ViewModel-dan UI-ga reaktiv ma'lumot uzatishning asosiy usuli sifatida ishlatiladi.
Asosiy fikrlar
LiveData — Android Jetpack kutubxonasidan hayotiy siklini hisobga oladigan Observer naqshini amalga oshiradigan sinf. Standart Observable yoki Flow-dan farqli o'laroq, LiveData obunalarni avtomatik boshqaradi: Observer faqat LifecycleOwner faol holatda (STARTED yoki RESUMED) bo'lganida bildirishnomalarni oladi. Hayotiy sikl egasi nofaol holatga (STOPPED yoki DESTROYED) o'tsa, obuna to'xtatiladi yoki olib tashlanadi.
LiveData Android Architecture Components (AAC) tarkibida 2017-yilda Google I/O konferensiyasida ViewModel va Room bilan birga taqdim etilgan. Asosiy maqsad — asinxron ma'lumotlar bilan ishlashda xotira oqishi muammosini bartaraf etish: dasturchilar tez-tez callback-lardan chiqishni unutishardi, bu esa yo'q qilingan Activity-larga havolalarni saqlab qolishga olib kelardi. LiveData chiqishni avtomatlashtiradi — LifecycleOwner bilan bog'langan Observer egasi yo'q qilinganidan keyin yangilanishlarni olmaydi.
Android Developers (2025) so'roviga ko'ra, LiveData joriy etilishidan oldin har ikkinchi crash yo'q qilingan UI kontrollerida metodlarni chaqirish bilan bog'liq edi. LiveData bu xato sinfini to'liq bartaraf qiladi. IT Sectr da biz LiveData-ni 2018-yildan boshlab barcha loyihalarga joriy qildik — 7 yil davomida Activity-ga eskirgan havola sababli bironta ham crash bo'lmadi.
LiveData-ning boshqa kuzatish konteynerlaridan asosiy farqi — Lifecycle bilan bog'liqligi. Kuzatuvchi yaratilganda LiveData LifecycleOwner statusini tekshiradi: agar status STARTED yoki RESUMED bo'lsa, Observer faol hisoblanadi va darhol yangilanishlarni oladi. Agar status PAUSED, STOPPED yoki DESTROYED bo'lsa, yangilanishlar faol holatga qaytgunga qadar yetkazilmaydi.
Mexanizm LifecycleBoundObserver sinfi orqali amalga oshiriladi, u addObserver() yordamida Lifecycle-da ro'yxatdan o'tadi. LifecycleOwner holatni o'zgartirganda onStateChanged() callback-i ishga tushadi va LiveData Observer faollik statusini yangilaydi. setValue() orqali ma'lumot o'rnatilganda LiveData kuzatuvchilar ro'yxatini kezadi va qiymatni faqat faollariga yetkazadi. Kuzatuvchi DESTROYED holatiga o'tganda Observer avtomatik ravishda obunachilar ro'yxatidan olib tashlanadi.
Android Jetpack hujjatlariga ko'ra (2025), LifecycleBoundObserver mexanizmi status tekshiruviga 0,5 µs dan kam sarflaydi — bu odatdagi UI yangilash operatsiyasi bilan solishtirganda ahamiyatsiz darajada kichik. Bu LiveData-ni yuqori chastotali yangilanishlar (taymerlar, hisoblagichlar) uchun ishlash pasayishi xavfisiz mos qiladi.
MutableLiveData — saqlangan qiymatni o'zgartirish uchun ochiq setValue() va postValue() metodlariga ega LiveData vorisi. LiveData-dan farqli o'laroq, MutableLiveData yozish uchun mavjud, ammo ViewModel-da faqat LiveData (o'zgarmas versiya) nashr etish, MutableLiveData-ni private modifikatori ostida yashirish odatiy holdir.
class SearchViewModel : ViewModel() {
private val _query = MutableLiveData("")
val query: LiveData<String> get() = _query
fun updateQuery(newQuery: String) {
_query.value = newQuery // setValue() — asosiy thread-da
}
fun updateFromNetwork(result: String) {
_query.postValue(result) // postValue() — istalgan thread-dan
}
}
setValue() faqat asosiy thread-dan chaqirilishi kerak — u darhol kuzatuvchilarga bildirish beradi. postValue() fon thread-dan chaqirish uchun xavfsiz: qiymatni asosiy thread navbatiga qo'yadi va kuzatuvchilarga asinxron bildirish beradi. Muhim: agar postValue() birinchisini qayta ishlashdan oldin ikki marta chaqirilsa, oraliq qiymat yo'qolishi mumkin — kuzatuvchilar faqat oxirgisini oladi. Barcha oraliq holatlarni (masalan, yuklanish jarayoni) uzatish uchun asosiy thread-da setValue() dan foydalaning.
Transformations.map() — Observer yozmasdan bir LiveData qiymatini boshqa turga funksional o'zgartirish. Masalan, LiveData<User> dan foydalanuvchi nomi bilan LiveData<String> olish. Transformatsiyalar len'ya: o'zgartirish faqat maqsadli LiveData-da faol Observer mavjud bo'lganda bajariladi.
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 — ikki manbani birlashtirish
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 oqimlar olamidan flatMap analogi: kirish LiveData o'zgarganda chiqish LiveData-ning yangi nusxasiga o'tadi. MediatorLiveData — bir nechta LiveData manbalarini yangilanish ustuvorligini boshqarish imkoniyati bilan birlashtirish uchun ilg'or vosita. Developer Survey (2024) ma'lumotiga ko'ra, MediatorLiveData turli manbalardan ma'lumotlarni agregatsiya qilish talab qilinadigan loyihalarning 35%-ida ishlatiladi — masalan, UI forma ma'lumotlari va server javobini birlashtirish.
liveData { } — korutina ichida LiveData qiymatini asinxron hisoblash imkonini beruvchi coroutine builder (lifecycle-livedata-ktx 2.2.0 da taqdim etilgan). liveData { } bloki ichida suspend konteksti, shuningdek qiymatlarni nashr etish uchun emit() funksiyasi mavjud. Builder ichida ishga tushirilgan barcha korutinlar barcha kuzatuvchilar nofaol bo'lganda avtomatik bekor qilinadi.
val userLiveData: LiveData<User> = liveData {
// Standartda Dispatchers.IO da bajariladi
val user = userRepository.fetchUser(userId)
// Natijani emit qilamiz — avtomatik asosiy thread-da
emit(user)
}
val progressLiveData: LiveData<Int> = liveData {
for (i in 0..100) {
emit(i)
delay(50)
}
}
liveData builder emitSource() funksiyasini qo'llab-quvvatlaydi — boshqa LiveData-ni manba sifatida emit qilish (korutina ichida switchMap analogi). Taym-aut: hech bir Observer 5 soniya (standart) faol bo'lmasa, korutina bekor qilinadi. Qayta faollashtirishda liveData { } boshidan bajariladi. Google ma'lumotiga ko'ra (Android Dev Summit 2024), liveData builder qo'lda ViewModel + LiveData boshqaruvi bilan solishtirganda 40% shablon kodini kamaytiradi.
Email va parol maydonlari, validatsiya va yuklanish holati bilan klassik kirish ekrani. ViewModel uchta LiveData-ni boshqaradi: email, password va 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("Barcha maydonlarni to'ldiring"))
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-ni DAO so'rovining qaytish turi sifatida qo'llab-quvvatlaydi: jadval har o'zgarganda LiveData avtomatik kuzatuvchilarga bildirish beradi, bu reaktiv UI uchun ideal.
@Dao
interface TaskDao {
@Query("SELECT * FROM tasks WHERE completed = 0")
fun getActiveTasks(): LiveData<List<Task>>
@Insert
suspend fun insertTask(task: Task)
}
// ViewModel da:
class TaskViewModel(application: Application) : AndroidViewModel(application) {
private val dao = AppDatabase.getDatabase(application).taskDao()
val activeTasks: LiveData<List<Task>> = dao.getActiveTasks()
}
Room tasks jadvalidagi o'zgarishlarni kuzatuvchi kodni yaratadi va har bir INSERT, UPDATE yoki DELETE da LiveData-ni avtomatik yangilaydi. Bu qo'shimcha kodsiz ishlaydi — faqat LiveData qaytish turi bilan @Query annotatsiyasi kifoya. IT Sectr da biz 2019-yildan Android loyihalarida lokal ma'lumot keshlash uchun Room + LiveData standart to'plamidan foydalanamiz.
Tez-tez beriladigan savollar
LiveData — ichki Lifecycle qo'llab-quvvatlashga ega kuzatish konteyneri: Observer avtomatik faollashadi/nofaollashadi. StateFlow — Kotlin Coroutines dan (Kotlinx Coroutines 1.3.7+) reaktiv oqim, Lifecycle-ga bog'liq emas, lekin buni stateIn(WhileSubscribed) orqali qo'llab-quvvatlaydi. StateFlow View-da hayotiy siklini aniq boshqarishni talab qiladi, lekin korutinlar, Flow operatorlari va ko'p platformalilikka kirish beradi. Google yangi Kotlin loyihalari uchun StateFlow-ni, Java kodi yoki eski kutubxonalar bilan moslik uchun LiveData-ni tavsiya qiladi.
lifecycle-livedata-ktx kutubxonasidan liveData.asFlow() kengaytma funksiyasidan foydalaning. U har o'zgarishda LiveData-ning joriy qiymatini emit qiluvchi Flow yaratadi. Keyin .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialValue) orqali StateFlow-ga aylantiring. Teskari aylantirish — stateFlow.asLiveData(). O'zaro konvertatsiya bir loyihada ikkala kutubxonaning afzalliklaridan foydalanish imkonini beradi.
postValue() kechiktirilgan qiymatni saqlash uchun AtomicReference dan foydalanadi. Agar postValue() asosiy thread tomonidan qayta ishlashdan oldin ikki marta chaqirilsa, birinchi qiymat ikkinchisi bilan yozib tashlanadi — Observable faqat oxirgisini oladi. Bu LiveData-ning ichki navbatga ega emasligi bilan bog'liq: u faqat bitta kechiktirilgan qiymatni saqlaydi. Har bir oraliq nuqtani (1%, 2%, … 100%) uzatish uchun asosiy thread-da setValue() yoki kotlinx-coroutines dan ConflatedFlow dan foydalaning.
Ha, LiveData-ni observeForever() orqali kuzatish mumkin, Observer-ni LifecycleOwnersiz uzatish bilan. Ammo bu holatda obunani bekor qilish removeObserver() orqali aniq bo'lishi kerak — avtomatik bekor qilish ishlamaydi. observeForever() LifecycleOwner mavjud bo'lmagan servislarda, ContentProvider da yoki ViewModel da qo'llaniladi. Google tavsiyasiga ko'ra, Activity/Fragment da observeForever() dan saqlaning — LifecycleOwner bilan observe() dan foydalaning.
Xatti-harakat xususiyati: LiveData yangi faol Observer olganida, darhol oxirgi qiymatni oladi (agar o'rnatilgan bo'lsa). LiveData-ning eski versiyalari (lifecycle 2.5.0 dan oldin) faol holatga o'tishda hatto nofaol obunachilarga ham qiymat yetkazardi — bu tuzatildi. Joriy versiyada LiveData oxirgi qiymatni nofaoldan faol holatga O'TISH vaqtida oladi, bu ekranlarni ishga tushirishni soddalashtiradi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.