درک LiveData


درک livedata

چرا LiveData؟

امروزه component های معماری برای توسعه دهندگان اندروید متداول هستند. برای مدت زیادی ست که هر کس نوعی معماری،  بر حسب نیاز پروژه خود انتخاب می کند. یکی از مهم ترین component ها در این میان LiveData می باشد. در این مقاله درباره اهمیت و چگونگی بکارگیری LiveData بحث می شود.

مشکل

به یاد دارید پیش از component های معماری و RxJava چگونه نتیجه یک بخش از برنامه یا callback ها را به UI thread اطلاع می دادیم؟ در درجه اول، به کمک interface ها

یک مثال ساده از برنامه ای که با معماری MVP توسعه یافته، بررسی می نماییم. پیش از این اگر در برنامه نیاز به صدا زدن یک API بود، این متد در لایه View و در بخش Presenter یک request را اجرا می نمود. سپس، در متدی جداگانه، به کمک Async task این عملیات انجام می گرفت. با دریافت response از سرور، به کمک یک interface آنرا به view منتقل خواهیم کرد.

با این روال، view و presenter و تعداد زیادی اینترفبیس با هم در تعامل خواهند بود. در واقع با انبوهی از کشاکش لایه ها رو به رو هستیم.

راه حل

راه حل این مشکل در پیاده سازی معماری MVVM می باشد. البته پیشتر در مقاله ای به بررسی و پیاده سازی این معماری پرداخته ایم. تاکید این مقاله بر درک LiveData و جایگزینی کاربرد interface با آن است.

LiveData چیست؟

با توجه به document ها اینگونه تعریف می گردد : LiveData نوعی observable برای نگهداری داده هاست. بر خلاف observable های متداول، LiveData از چرخه زندگی خود آگاه است. به این معنی که هرگونه چرخه حیات componentها، اکتیویتی ها، فرگمنت ها و سرویس هایی که در خود دارد را مدیریت می کند. همین امر باعث می شود LiveData بخش هایی از برنامه را آپدیت کند که در بخش معینی از چرخه زندگی خود باشند.

عملکرد LiveData

برای درک Live Data ابتدا باید الگوی Observer را درک نمود. در این الگو (design pattern) به کمک یک object رویدادی صدا زده می شود که حاوی لیستی از dependencyها در خود می باشد، observerها صدا زده می شود. بطور خودکار تغییر وضعیت های پیش آمده به آنها اعلام می گردد.

به همین منوال نیازی نیست هربار درخواستی برای چک کردن آخرین وضعیت داده ها ترتیب داد. هنگام استفاده از معماری MVVM ارتباط میان ViewModel و View به کمک LiveData صورت می پذیرد.

از اکتیوتی یا فرگمنت مورد نظر، وضعیت observer و مرحله ای که چرخه حیات در آن قرار دارد را به LiveData پاس می دهیم. اما نیازی به ساخت یا از بین بردن لیستی از این موارد نیست. خود LiveData این موارد را مدیریت می نماید.

در واقع LiveData مقادیر را به اکتیویتی ها یا فرگمنت ها(به کمک observerها) می فرستد. اگر در وضعیت foreground باشند، هیچ گونه نشت حافظه ای رخ نمی دهد. نیازی به چک کردن حیات یا عدم حیات View نیست. هم چنین نیازی به آپدیت UI درون observer نمی باشد.

درک livedata

دو مورد مهمی که باید درباره LiveData بدانیم :

  • UI یا View که شامل یک اکتیویتی یا فرگمنت باشد هر بار که تغییری در داده ها رخ دهد باخبر خواهند شد. بدون اینکه لازم باشد هر بار تغییرات داده ای از ViewModel چک شوند.
  • اینکه LiveData به خودی خود چرخه حیات component های درون خود را مدیریت می کند از نشت حافظه یا خطاهایی مثل NullPointerException جلوگیری می نماید.

 

LiveData در دل کد

برای بکارگیری LiveData درون پروژه مراحل زیر را دنبال می کنیم :

  • تعیین dependency های مربوطه درون gradle
  • ساخت یک نمونه از Live Data به منظور نگهداری نوع خاصی از داده. این کار معمولا درون کلاس ViewModel انجام می شود.
  • ساخت یک object از نوع observer که متد onChanged() را تعریف کند. که به کمک آن تغییرات پیش آمده برای شی Live Data نگهداری شود. به طور معمول شی observer در UI controller مثل اکتیویتی یا فرگمنت ساخته می شود.
  • شی observer به کمک متد   observe()به Live Data ملحق می شود. همین متد روی چرخه حیات component ها نظارت دارد.

مشخص نمودن dependencyها

//Java
implementation "android.arch.lifecycle:extensions:1.0.0"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0"

//Kotlin with AndroidX
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'

 

ساخت نمونه LiveData

Live Data هر نوعی از داده ها را درون خود نگه می دارد، شامل collection ها مثل انواع لیست هاست. معمولا یک شی LiveData به کمک یک شی ViewModel نگهداری می شود و از طریق متد getter می توان به آن دسترسی داشت.

package com.example.viewmodel
  

  import androidx.lifecycle.LiveData
  import androidx.lifecycle.MutableLiveData
  import androidx.lifecycle.ViewModel
  

  class SampleViewModel (val name:String): ViewModel() {
  

      private val _nameLiveData = MutableLiveData<String>()
  

      val nameLiveData: LiveData<String>
          get() = _nameLiveData
  

      fun setFirstName() {
          _nameLiveData.postValue( name)
      }
  

    
  }

به محض صدا کردن متد setFirstName() مقادیر Live Data آپدیت می گردد.

ساخت یک observer برای LiveData در UI

یک اکتیویتی ساخته و هر گونه تغییر در LiveData، مانند قطعه کد زیر، مدیریت می شود :

package com.example.viewmodel
  

  import android.os.Bundle
  import android.widget.Toast
  import androidx.appcompat.app.AppCompatActivity
  import androidx.lifecycle.Observer
  import androidx.lifecycle.ViewModelProvider
  import kotlinx.android.synthetic.main.activity_main.*
  

  class MainActivity : AppCompatActivity() {
  

      lateinit var viewModel: SampleViewModel
  

      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_main)
          viewModel = ViewModelProvider(this).get(SampleViewModel::class.java)
          observeViewModel()
          initListeners()
      }
  

      private fun initListeners() {
          btn_badge?.setOnClickListener {
              viewModel.setFirstName()
          }
      }
  

      private fun observeViewModel() {
  

          viewModel.nameLiveData.observe(this, Observer {
              showToast(it)
          })
  

      }
  

      private fun showToast(value: String) {
          Toast.makeText(this, value, Toast.LENGTH_LONG).show()
      }
  

  }

به روز رسانی مقادیر LiveData

برای این منظور دو راه وجود دارد:

  • setValue
  • postValue
setValue

باید از متد setValue(T) برای آپدیت شی LiveData از خود main thread استفاده نمود. اگر از متد setValue در ترد پیش زمینه استفاده کنیم برنامه crash خواهد کرد و استثنایی از نوع WongThread ایجاد می کند.

_nameLiveData.value = “something”

postValue

اگر قطعه کد در یک thread استخدام شده در برنامه (worker thread) اجرا شود، در thread اصلی می توان از متد postValue(T) برای به روز رسانی استفاده کرد. در هر threadی می توان از این روش استفاده کرد اما ترجیه روی thread اصلی ست چرا که کمی کندتر از setValue ست.

_nameLiveData.postValue("something")

برای به روز رسانی LiveData در thread اصلی از setValue و در سایر threadها از postValue استفاده کنید تا شاهد پرفورمنس بهتری باشید.

مثال کاربردی

فرض کنید برنامه ای باشد که با باز نمودن یک اکتیویتی توسط کاربر و کلیک بر دکمه ای، بنا باشد یک  API صدا زده شود و پاسخی برای کاربر از سرور گرفته شود. پس از دریافت پاسخ بوسیله LiveData نتیجه به UI پاس داده می شود تا view به روز رسانی شود. در این مثال، هنگامی که صدا زدن API در حال انجام می باشد، برنامه به گونه به وضعیت پس زمینه می رود. حالا به نظر شما برنامه کرش می کند یا UI به روز رسانی می گردد؟

صدا زدن API کامل می شود و LiveData مقدار را دریافت می نماید. با این حال نه برنامه crash می کند و نه UI به روز رسانی می گردد. همانطور که اشاره کردیم Live Data از وضعیت چرخه حیات componentهای درون خود، آگاه است. پس زمانی که صدا زدن API تمام می شود و LiveData مقدار را دریافت می کند اما به UI منتقل نمی کند. بلکه صبر می کند تا وضعیت UI contoroler از حالت پس زمینه به foreground تبدیل شود و Live Data بلافاصله UI را با آخرین مقدار آپدیت می نماید.

به این پست امتیاز دهید

روی ستاره های کلیک کنید و امتیاز بدید

میانگین امتیاز / 5. تعداد:

2 دیدگاه در نوشته: “درک LiveData

  1. AffiliateLabz گفت:

    Great content! Super high-quality! Keep it up! 🙂

    1. نسیم نژند گفت:

      Your support is greatly appreciated 🙂

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

Enter Captcha Here : *

Reload Image