LiveData: چیست، کامپوننت Android Architecture

نویسنده: IT Sectr منتشر شده: 2026-02-20 زمان مطالعه: 8 دقیقه

LiveData — یک محفظه داده قابل مشاهده از Android Jetpack است که چرخه حیات Activity، Fragment یا Service را در نظر می‌گیرد. بررسی می‌کنیم که LiveData چگونه اشتراک‌ها را خودکار مدیریت می‌کند: مشترکین فعال به‌روزرسانی دریافت می‌کنند و غیرفعال‌ها نه، که نشت حافظه و کرش‌های ناشی از ارجاعات منسوخ را از بین می‌برد. طبق داده‌های Google (Android Developers, 2025)، LiveData در 74% پروژه‌های Java و Kotlin به عنوان روش اصلی انتقال واکنش‌گرای داده از ViewModel به UI استفاده می‌شود.

نکات اصلی

  • LiveData — محفظه داده قابل مشاهده با در نظر گرفتن چرخه حیات: هنگام غیرفعال بودن مشترک به طور خودکار لغو اشتراک می‌کند.
  • MutableLiveData — نسخه قابل تغییر LiveData با متدهای setValue() (رشته اصلی) و postValue() (رشته پس‌زمینه).
  • Observer — رابطی که هنگام تغییر داده، تا زمانی که LifecycleOwner در حالت فعال است، به‌روزرسانی دریافت می‌کند.
  • تبدیل‌های map() و switchMap() — زنجیره‌های تابعی تبدیل LiveData بدون ایجاد کلاس‌های جدید.
  • MediatorLiveData — ترکیب چندین منبع LiveData در یک جریان با مدیریت اولویت.

LiveData در Android چیست؟

LiveData — کلاسی از کتابخانه Android Jetpack است که الگوی Observer را با در نظر گرفتن چرخه حیات پیاده‌سازی می‌کند. برخلاف Observable یا Flow استاندارد، LiveData اشتراک‌ها را خودکار مدیریت می‌کند: Observer فقط زمانی که LifecycleOwner در حالت فعال است (STARTED یا RESUMED) اعلان دریافت می‌کند. اگر مالک چرخه حیات به حالت غیرفعال (STOPPED یا DESTROYED) برود، اشتراک متوقف یا حذف می‌شود.

LiveData در Android Architecture Components (AAC) در سال ۲۰۱۷ در Google I/O همراه با ViewModel و Room معرفی شد. انگیزه اصلی از بین بردن مشکل نشت حافظه هنگام کار با داده‌های ناهمگام بود: توسعه‌دهندگان اغلب فراموش می‌کردند از callback‌ها لغو اشتراک کنند که منجر به نگه‌داری ارجاع به Activity‌های نابود شده می‌شد. LiveData لغو اشتراک را خودکار می‌کند — Observer متصل به LifecycleOwner پس از نابود شدن مالک، به‌روزرسانی دریافت نمی‌کند.

طبق نظرسنجی Android Developers (2025)، هر دومین کرش قبل از پیاده‌سازی LiveData مربوط به فراخوانی متدها روی کنترلر UI نابود شده بود. LiveData این دسته از خطاها را کاملاً از بین می‌برد. در IT Sectr ما LiveData را از سال ۲۰۱۸ در تمام پروژه‌ها پیاده‌سازی کردیم — در ۷ سال حتی یک کرش به دلیل ارجاع منسوخ به Activity رخ نداده است.

LiveData و Lifecycle: اشتراک خودکار چگونه کار می‌کند

تفاوت کلیدی LiveData با سایر محفظه‌های قابل مشاهده — اتصال به Lifecycle است. هنگام ایجاد مشاهده‌گر، LiveData وضعیت LifecycleOwner را بررسی می‌کند: اگر وضعیت STARTED یا RESUMED باشد، Observer فعال در نظر گرفته می‌شود و بلافاصله به‌روزرسانی دریافت می‌کند. اگر وضعیت PAUSED، STOPPED یا DESTROYED باشد، به‌روزرسانی‌ها تا بازگشت به حالت فعال تحویل داده نمی‌شوند.

مکانیزم از طریق کلاس LifecycleBoundObserver پیاده‌سازی می‌شود که با addObserver() در Lifecycle ثبت می‌شود. وقتی LifecycleOwner حالت را تغییر می‌دهد، callback onStateChanged() فراخوانی می‌شود و LiveData وضعیت فعالیت Observer را به‌روز می‌کند. هنگام تنظیم داده از طریق setValue()، LiveData لیست مشاهده‌گرها را مرور می‌کند و مقدار را فقط به مشاهده‌گرهای فعال تحویل می‌دهد. وقتی مشاهده‌گر به حالت DESTROYED می‌رود، Observer به طور خودکار از لیست مشترکین حذف می‌شود.

طبق مستندات Android Jetpack (2025)، مکانیزم LifecycleBoundObserver کمتر از ۰٫۵ میکروثانیه برای بررسی وضعیت مصرف می‌کند — سربار در مقایسه با عملیات معمول به‌روزرسانی UI ناچیز است. این باعث می‌شود LiveData برای به‌روزرسانی‌های با فرکانس بالا (تایمرها، شمارنده‌ها) بدون خطر کاهش عملکرد مناسب باشد.

MutableLiveData: setValue در مقابل postValue

MutableLiveData — وارث LiveData با متدهای عمومی setValue() و postValue() برای تغییر مقدار ذخیره شده. برخلاف LiveData، MutableLiveData برای نوشتن در دسترس است، اما در ViewModel مرسوم است که فقط LiveData (نسخه غیرقابل تغییر) منتشر شود و MutableLiveData زیر modificator private پنهان شود.

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

    fun updateQuery(newQuery: String) {
        _query.value = newQuery  // setValue() — در رشته اصلی
    }

    fun updateFromNetwork(result: String) {
        _query.postValue(result)  // postValue() — از هر رشته‌ای
    }
}

setValue() فقط از رشته اصلی (main thread) فراخوانی شود — بلافاصله به مشاهده‌گرها اعلان می‌دهد. postValue() برای فراخوانی از رشته پس‌زمینه امن است: مقدار را در صف رشته اصلی قرار می‌دهد و به صورت ناهمگام به مشاهده‌گرها اعلان می‌دهد. مهم: اگر postValue() دو بار پشت سر هم قبل از پردازش اولی فراخوانی شود، مقدار میانی ممکن است از دست برود — مشاهده‌گرها فقط آخرین مقدار را دریافت می‌کنند. برای انتقال تمام حالات میانی (مثلاً پیشرفت بارگذاری) از setValue() در رشته اصلی استفاده کنید.

تبدیل‌های LiveData: map، switchMap، MediatorLiveData

Transformations.map() — تبدیل تابعی مقدار یک LiveData به نوع دیگر بدون نوشتن Observer. مثلاً از LiveData<User> به LiveData<String> با نام کاربر. تبدیل‌ها تنبل هستند: تبدیل فقط زمانی انجام می‌شود که Observer فعال روی 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 — ترکیب دو منبع
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() — مشابه flatMap از دنیای جریان‌های واکنش‌گرا: با تغییر LiveData ورودی، به نمونه جدیدی از LiveData خروجی سوئیچ می‌کند. MediatorLiveData — ابزار پیشرفته برای ترکیب چندین منبع LiveData با قابلیت مدیریت اولویت به‌روزرسانی. طبق Developer Survey (2024)، MediatorLiveData در 35% پروژه‌هایی که نیاز به تجمیع داده از منابع مختلف دارند استفاده می‌شود — مثلاً ترکیب داده‌های فرم UI و پاسخ سرور.

LiveData با کروتین‌ها: liveData builder

liveData { } — coroutine builder (ظاهر شده در lifecycle-livedata-ktx 2.2.0) که امکان محاسبه ناهمگام مقدار LiveData در داخل کروتین را فراهم می‌کند. در داخل بلوک liveData { } زمینه suspend و همچنین تابع emit() برای انتشار مقادیر در دسترس است. تمام کروتین‌های راه‌اندازی شده داخل builder به طور خودکار هنگام غیرفعال بودن همه مشاهده‌گرها لغو می‌شوند.

kotlin
val userLiveData: LiveData<User> = liveData {
    // به طور پیش‌فرض روی Dispatchers.IO اجرا می‌شود
    val user = userRepository.fetchUser(userId)
    // نتیجه را منتشر می‌کنیم — به طور خودکار روی رشته اصلی
    emit(user)
}

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

liveData builder از emitSource() پشتیبانی می‌کند — انتشار LiveData دیگر به عنوان منبع (مشابه switchMap در داخل کروتین). تایم‌اوت: اگر هیچ Observer به مدت ۵ ثانیه (پیش‌فرض) فعال نباشد، کروتین لغو می‌شود. پس از فعال‌سازی مجدد، liveData { } از ابتدا اجرا می‌شود. طبق Google (Android Dev Summit 2024)، liveData builder ۴۰% کد الگویی را در مقایسه با مدیریت دستی ViewModel + LiveData کاهش می‌دهد.

مثال‌های کد: LiveData در Kotlin

مثال ۱: ViewModel با LiveData برای صفحه ورود

صفحه ورود کلاسیک با فیلدهای ایمیل و رمز عبور، اعتبارسنجی و حالت بارگذاری. ViewModel سه LiveData را مدیریت می‌کند: email، password و 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("همه فیلدها را پر کنید"))
            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)
            }
        }
    }
}

مثال ۲: LiveData با Room و کروتین‌ها

Room از LiveData به عنوان نوع بازگشتی کوئری DAO پشتیبانی می‌کند: با هر تغییر در جدول، LiveData به طور خودکار به مشاهده‌گرها اعلان می‌دهد که برای UI واکنش‌گرا ایده‌آل است.

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

    @Insert
    suspend fun insertTask(task: Task)
}

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

Room کدی تولید می‌کند که تغییرات جدول tasks را ردیابی می‌کند و LiveData را در هر INSERT، UPDATE یا DELETE به طور خودکار به‌روز می‌کند. این بدون کد اضافی کار می‌کند — فقط annotation @Query با نوع بازگشتی LiveData کافی است. در IT Sectr ما از Room + LiveData به عنوان پشته استاندارد برای ذخیره محلی داده در پروژه‌های Android از سال ۲۰۱۹ استفاده می‌کنیم.

سوالات متداول

تفاوت بین LiveData و StateFlow چیست؟

LiveData — محفظه قابل مشاهده با پشتیبانی داخلی Lifecycle: Observer به طور خودکار فعال/غیرفعال می‌شود. StateFlow — جریان واکنش‌گرا از Kotlin Coroutines (Kotlinx Coroutines 1.3.7+)، غیرمتصل به Lifecycle، اما از آن از طریق stateIn(WhileSubscribed) پشتیبانی می‌کند. StateFlow نیاز به مدیریت صریح چرخه حیات در View دارد، اما به کروتین‌ها، عملگرهای Flow و چندسکویی دسترسی می‌دهد. Google StateFlow را برای پروژه‌های جدید در Kotlin توصیه می‌کند و LiveData را برای کد Java یا هنگام نیاز به سازگاری با کتابخانه‌های قدیمی.

چگونه LiveData را به StateFlow تبدیل کنیم؟

از تابع توسعه‌ای liveData.asFlow() از کتابخانه lifecycle-livedata-ktx استفاده کنید. آن Flowای ایجاد می‌کند که مقدار فعلی LiveData را در هر تغییر منتشر می‌کند. سپس از طریق .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialValue) به StateFlow تبدیل کنید. تبدیل معکوس — stateFlow.asLiveData(). تبدیل متقابل امکان استفاده از مزایای هر دو کتابخانه را در یک پروژه فراهم می‌کند.

چه زمانی LiveData داده را در postValue از دست می‌دهد؟

postValue() از AtomicReference برای ذخیره مقدار به تأخیر افتاده استفاده می‌کند. اگر postValue() دو بار قبل از پردازش توسط رشته اصلی فراخوانی شود، مقدار اول توسط دوم بازنویسی می‌شود — Observable فقط آخرین مقدار را دریافت می‌کند. این به دلیل نداشتن صف داخلی LiveData است: فقط یک مقدار به تأخیر افتاده ذخیره می‌کند. برای انتقال هر نقطه میانی (۱٪، ۲٪، … ۱۰۰٪) از setValue() در رشته اصلی یا ConflatedFlow از kotlinx-coroutines استفاده کنید.

آیا می‌توان از LiveData بدون LifecycleOwner استفاده کرد؟

بله، LiveData را می‌توان از طریق observeForever() مشاهده کرد و Observer را بدون LifecycleOwner ارسال کرد. اما در این حالت لغو اشتراک باید صریح از طریق removeObserver() انجام شود — لغو اشتراک خودکار کار نمی‌کند. observeForever() در سرویس‌ها، ContentProvider یا ViewModel که LifecycleOwner در دسترس نیست استفاده می‌شود. طبق توصیه Google، از observeForever() در Activity/Fragment خودداری کنید — از observe() با LifecycleOwner استفاده کنید.

LiveData نسخه ۱٫۰ چیست (همیشه به‌روز)؟

ویژگی رفتار: وقتی LiveData یک Observer فعال جدید دریافت می‌کند، بلافاصله آخرین مقدار را دریافت می‌کند (اگر تنظیم شده باشد). نسخه‌های قدیمی LiveData (قبل از lifecycle 2.5.0) مقدار را حتی به مشترکین غیرفعال هنگام انتقال به حالت فعال تحویل می‌دادند — این رفع شده است. در نسخه فعلی LiveData آخرین مقدار را هنگام انتقال FROM غیرفعال TO فعال دریافت می‌کند که مقداردهی اولیه صفحه‌ها را ساده‌تر می‌کند.

خلاصه

  • LiveData — محفظه داده قابل مشاهده با اتصال خودکار به Lifecycle که نشت حافظه و کرش‌های ناشی از ارجاعات منسوخ را از بین می‌برد.
  • MutableLiveData با setValue() (رشته اصلی) و postValue() (رشته پس‌زمینه) — API اصلی برای تغییر داده.
  • تبدیل‌های map()، switchMap() و MediatorLiveData — زنجیره‌های تابعی بدون کد الگویی.
  • liveData builder liveData { } — رویکرد کروتینی برای ایجاد LiveData ناهمگام با لغو خودکار کروتین‌ها.
  • Room + LiveData — اتصال آماده برای ذخیره محلی بدون کد اضافی در DAO.
  • LiveData در ۷۴٪ پروژه‌های Jetpack استفاده می‌شود و استاندارد برای کد Java و معماری‌های Legacy باقی می‌ماند.
  • برای پروژه‌های جدید Kotlin، Google StateFlow را توصیه می‌کند، اما LiveData راه‌حل سازگاری برای پشته‌های ترکیبی باقی می‌ماند.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید