نمای کلی LiveData   بخشی از Android Jetpack.

LiveData یک کلاس نگهدارنده داده قابل‌مشاهده است. برخلاف یک قابل‌مشاهده معمولی، LiveData از چرخه حیات آگاه است، به این معنی که به چرخه حیات سایر اجزای برنامه، مانند فعالیت‌ها، قطعات، یا خدمات احترام می‌گذارد. این آگاهی تضمین می‌کند که LiveData فقط ناظران مؤلفه برنامه را که در وضعیت چرخه حیات فعال هستند به‌روز می‌کند.

‫LiveData ناظری را که با کلاس Observer نشان داده می‌شود، درصورتی در حالت فعال درنظر می‌گیرد که چرخه حیات آن در حالت STARTED یا RESUMED باشد. LiveData فقط ناظران فعال را درباره به‌روزرسانی‌ها مطلع می‌کند. ناظران غیرفعال ثبت‌شده برای تماشای اشیاء LiveData از تغییرات مطلع نمی‌شوند.

می‌توانید ناظری را که با شیء پیاده‌سازی‌کننده میانای LifecycleOwner جفت شده است ثبت کنید. این رابطه اجازه می‌دهد وقتی وضعیت شیء Lifecycle مربوطه به DESTROYED تغییر می‌کند، ناظر برداشته شود. این به‌ویژه برای فعالیت‌ها و قطعه‌ها مفید است زیرا می‌توانند به‌طور ایمن اشیاء LiveData را مشاهده کنند و نگران نشت نباشند—فعالیت‌ها و قطعه‌ها فوراً لغو اشتراک می‌شوند وقتی چرخه‌های حیات آن‌ها نابود می‌شود.

برای اطلاعات بیشتر درباره نحوه استفاده از LiveData، به کار با اشیاء LiveData مراجعه کنید.

مزایای استفاده از LiveData

استفاده از LiveData مزایای زیر را به‌همراه دارد:

مطمئن می‌شود که واسط کاربر با وضعیت داده‌های شما مطابقت دارد
‫
LiveData از الگوی ناظر پیروی می‌کند. وقتی داده‌های اساسی تغییر می‌کند، LiveData به اشیای Observer اطلاع می‌دهد. می‌توانید کدتان را برای به‌روزرسانی واسط کاربر در این Observer شیء ادغام کنید. به این ترتیب، نیازی نیست هر بار که داده‌های برنامه تغییر می‌کند، واسط کاربر را به‌روز کنید، زیرا ناظر این کار را برای شما انجام می‌دهد.
بدون نشت حافظه
ناظران به Lifecycle شیءها محدود هستند و وقتی چرخه حیات مرتبط با آن‌ها ازبین می‌رود، خودشان را پاک می‌کنند.
بدون خرابی به‌دلیل فعالیت‌های متوقف‌شده
اگر چرخه حیات ناظر غیرفعال باشد، مثلاً درمورد فعالیتی در پشته قبلی‌ها، هیچ رویداد LiveData دریافت نمی‌کند.
دیگر نیازی به مدیریت دستی چرخه حیات نیست
مؤلفه‌های میانای کاربری فقط داده‌های مربوطه را مشاهده می‌کنند و مشاهده را متوقف یا ازسر نمی‌گیرند. ‫LiveData به‌طور خودکار همه این موارد را مدیریت می‌کند زیرا از تغییرات وضعیت چرخه حیات مربوطه درحین مشاهده آگاه است.
داده‌های همیشه به‌روز
اگر چرخه حیات غیرفعال شود، پس‌از فعال شدن مجدد، جدیدترین داده‌ها را دریافت می‌کند. برای مثال، فعالیتی که در پس‌زمینه بوده است، بلافاصله پس‌از بازگشت به پیش‌زمینه، جدیدترین داده‌ها را دریافت می‌کند.
تغییرات پیکربندی مناسب
اگر فعالیت یا قطعه‌ای به‌دلیل تغییر پیکربندی، مانند چرخش دستگاه، دوباره ایجاد شود، بلافاصله جدیدترین داده‌های دردسترس را دریافت می‌کند.
منابع هم‌رسانی
می‌توانید شیء LiveData را بااستفاده از الگوی تک‌قلو گسترش دهید تا خدمات سیستم را دربرگیرد و بتوان آن‌ها را در برنامه‌تان هم‌رسانی کرد. شیء LiveData یک‌بار به خدمات سیستم متصل می‌شود و سپس هر ناظری که به منبع نیاز داشته باشد می‌تواند شیء LiveData را تماشا کند. برای اطلاعات بیشتر، به گسترش LiveData مراجعه کنید.

کار کردن با اشیاء LiveData

برای کار با اشیاء LiveData، این مراحل را دنبال کنید:

  1. نمونه‌ای از LiveData برای نگهداری نوع خاصی از داده‌ها ایجاد کنید. این کار معمولاً در کلاس ViewModel انجام می‌شود.
  2. شیء Observer ایجاد کنید که روش onChanged() را تعریف می‌کند. این روش کنترل می‌کند که وقتی داده‌های نگه‌داشته‌شده شیء LiveData تغییر می‌کند چه اتفاقی می‌افتد. معمولاً یک شیء Observer را در یک کنترل‌کننده میانای کاربر، مانند یک فعالیت یا قطعه، ایجاد می‌کنید.
  3. شیء Observer را بااستفاده از روش observe() به شیء LiveData پیوست کنید. روش observe() یک شیء LifecycleOwner می‌گیرد. این کار شیء Observer را در شیء LiveData مشترک می‌کند تا از تغییرات مطلع شود. معمولاً شیء Observer را در یک کنترل‌کننده واسط کاربر، مانند فعالیت یا قطعه، پیوست می‌کنید.

وقتی مقدار ذخیره‌شده در شیء LiveData را به‌روز می‌کنید، تا زمانی که LifecycleOwner پیوست‌شده در حالت فعال باشد، همه ناظران ثبت‌شده را راه‌اندازی می‌کند.

LiveData به ناظران کنترل‌کننده میانای کاربر اجازه می‌دهد تا در به‌روزرسانی‌ها مشترک شوند. وقتی داده‌های موجود در شیء LiveData تغییر می‌کند، واسط کاربر به‌طور خودکار در پاسخ به‌روز می‌شود.

ایجاد کردن اشیای LiveData

‫LiveData یک پوشاننده است که می‌تواند با هر داده‌ای استفاده شود، ازجمله اشیایی که Collections را پیاده‌سازی می‌کنند، مانند List. شیء LiveData معمولاً در شیء ViewModel ذخیره می‌شود و ازطریق روش getter قابل‌دسترسی است، همان‌طور که در مثال زیر نشان داده شده است:

کاتلین

class NameViewModel : ViewModel() {

    // Create a LiveData with a String
    val currentName: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }

    // Rest of the ViewModel...
}

جاوا

public class NameViewModel extends ViewModel {

    // Create a LiveData with a String
    private MutableLiveData<String> currentName;

    public MutableLiveData<String> getCurrentName() {
        if (currentName == null) {
            currentName = new MutableLiveData<String>();
        }
        return currentName;
    }

    // Rest of the ViewModel...
}

در ابتدا، داده‌ها در شیء LiveData تنظیم نشده است.

می‌توانید درباره مزایا و کاربرد کلاس ViewModel در راهنمای ViewModel بیشتر بخوانید.

مشاهده اشیاء LiveData

در اکثر موارد، روش onCreate() مؤلفه برنامه مکان مناسبی برای شروع مشاهده شیء LiveData به‌دلایل زیر است:

  • برای اطمینان از اینکه سیستم تماس‌های زائد از فعالیت یا روش onResume() قطعه برقرار نمی‌کند.
  • برای اطمینان از اینکه فعالیت یا قطعه داده‌هایی دارد که می‌تواند به‌محض فعال شدن نمایش دهد. به‌محض اینکه مؤلفه برنامه در وضعیت STARTED قرار می‌گیرد، جدیدترین مقدار را از اشیاء LiveData که مشاهده می‌کند دریافت می‌کند. این فقط زمانی اتفاق می‌افتد که شیء LiveData برای مشاهده تنظیم شده باشد.

به‌طور کلی، LiveData به‌روزرسانی‌ها را فقط زمانی ارائه می‌دهد که داده‌ها تغییر کنند و فقط به ناظران فعال. یک استثنا برای این رفتار این است که ناظران همچنین زمانی که از حالت غیرفعال به فعال تغییر می‌کنند، به‌روزرسانی دریافت می‌کنند. علاوه‌براین، اگر ناظر برای بار دوم از غیرفعال به فعال تغییر کند، فقط درصورتی به‌روزرسانی دریافت می‌کند که مقدار از آخرین باری که فعال شده است تغییر کرده باشد.

نمونه کد زیر نحوه شروع مشاهده شیء LiveData را نشان می‌دهد:

کاتلین

class NameActivity : AppCompatActivity() {

    // Use the 'by viewModels()' Kotlin property delegate
    // from the activity-ktx artifact
    private val model: NameViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Other code to setup the activity...

        // Create the observer which updates the UI.
        val nameObserver = Observer<String> { newName ->
            // Update the UI, in this case, a TextView.
            nameTextView.text = newName
        }

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        model.currentName.observe(this, nameObserver)
    }
}

جاوا

public class NameActivity extends AppCompatActivity {

    private NameViewModel model;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Other code to setup the activity...

        // Get the ViewModel.
        model = new ViewModelProvider(this).get(NameViewModel.class);

        // Create the observer which updates the UI.
        final Observer<String> nameObserver = new Observer<String>() {
            @Override
            public void onChanged(@Nullable final String newName) {
                // Update the UI, in this case, a TextView.
                nameTextView.setText(newName);
            }
        };

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        model.getCurrentName().observe(this, nameObserver);
    }
}

پس‌از اینکه observe() با nameObserver که به‌عنوان پارامتر ارسال شده است فراخوانی شد، onChanged() فوراً فراخوانی می‌شود و جدیدترین مقدار ذخیره‌شده در mCurrentName را ارائه می‌دهد. اگر شیء LiveData مقداری در mCurrentName تنظیم نکرده باشد، onChanged() فراخوانی نمی‌شود.

به‌روزرسانی اشیای LiveData

LiveData هیچ روش دردسترس عمومی‌ای برای به‌روزرسانی داده‌های ذخیره‌شده ندارد. کلاس MutableLiveData روش‌های setValue(T) و postValue(T) را به‌صورت عمومی نمایش می‌دهد و اگر لازم است مقدار ذخیره‌شده در شیء LiveData را ویرایش کنید، باید از این روش‌ها استفاده کنید. معمولاً MutableLiveData در ViewModel استفاده می‌شود و سپس ViewModel فقط اشیای تغییرناپذیر LiveData را برای ناظران آشکار می‌کند.

پس‌از راه‌اندازی رابطه ناظر، می‌توانید مقدار شیء LiveData را به‌روز کنید، همان‌طور که در مثال زیر نشان داده شده است، که وقتی کاربر روی دکمه‌ای تک‌ضرب می‌زند، همه ناظران را فعال می‌کند:

کاتلین

button.setOnClickListener {
    val anotherName = "John Doe"
    model.currentName.setValue(anotherName)
}

جاوا

button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        String anotherName = "John Doe";
        model.getCurrentName().setValue(anotherName);
    }
});

فراخوانی setValue(T) در مثال منجر به فراخوانی ناظران می‌شود onChanged() روش‌هایی با مقدار John Doe. این مثال فشار دادن دکمه را نشان می‌دهد، اما setValue() یا postValue() می‌تواند برای به‌روزرسانی mName به دلایل مختلفی فراخوانی شود، ازجمله در پاسخ به درخواست شبکه یا تکمیل بارگذاری پایگاه داده؛ در همه موارد، فراخوانی setValue() یا postValue() ناظران را راه‌اندازی می‌کند و رابط کاربری را به‌روز می‌کند.

استفاده از LiveData با Room

کتابخانه پایداری Room از پُرسمان‌های قابل‌مشاهده پشتیبانی می‌کند که اشیای LiveData را برمی‌گردانند. پُرسمان‌های قابل‌مشاهده به‌عنوان بخشی از «شیء دسترسی به پایگاه داده» (DAO) نوشته می‌شوند.

Room همه کدهای لازم را برای به‌روزرسانی شیء LiveData هنگام به‌روزرسانی پایگاه داده تولید می‌کند. کد تولیدشده درصورت نیاز پُرسمان را به‌صورت ناهمگام در رشته پس‌زمینه اجرا می‌کند. این الگو برای همگام نگه داشتن داده‌های نمایش‌داده‌شده در میانای کاربر با داده‌های ذخیره‌شده در پایگاه داده مفید است. می‌توانید اطلاعات بیشتری درباره Room و DAO در راهنمای کتابخانه پایداری Room بخوانید.

استفاده از روال‌های مشترک با LiveData

LiveData شامل پشتیبانی از روال‌های هم‌زمان Kotlin است. برای اطلاعات بیشتر، استفاده از روال‌های مشترک Kotlin با مؤلفه‌های معماری Android را ببینید.

LiveData در معماری برنامه

LiveData از چرخه حیات آگاه است و چرخه حیات موجودیت‌هایی مانند فعالیت‌ها و قطعه‌ها را دنبال می‌کند. از LiveData برای برقراری ارتباط بین این مالکان چرخه حیات و اشیای دیگر با طول عمر متفاوت، مانند اشیای ViewModel، استفاده کنید. مسئولیت اصلی ViewModel بار کردن و مدیریت داده‌های مربوط به میانای کاربر است، که آن را به گزینه‌ای عالی برای نگهداری اشیای LiveData تبدیل می‌کند. اشیاء LiveData را در ViewModel ایجاد کنید و از آن‌ها برای نمایش وضعیت به لایه واسط کاربر استفاده کنید.

فعالیت‌ها و قطعه‌ها نباید نمونه‌های LiveData را نگه دارند زیرا نقش آن‌ها نمایش داده‌ها است، نه نگهداری وضعیت. همچنین، آزاد نگه داشتن فعالیت‌ها و قطعه‌ها از نگهداری داده‌ها، نوشتن آزمون‌های واحد را آسان‌تر می‌کند.

ممکن است وسوسه شوید که با اشیاء LiveData در کلاس لایه داده‌تان کار کنید، اما LiveData برای مدیریت جریان‌های ناهمگام داده طراحی نشده است. هرچند می‌توانید از تبدیل‌های LiveData و MediatorLiveData برای دستیابی به این هدف استفاده کنید، این رویکرد معایبی دارد: قابلیت ترکیب کردن جریان‌های داده بسیار محدود است و همه اشیای LiveData (ازجمله اشیای ایجادشده ازطریق تبدیل‌ها) در رشته اصلی مشاهده می‌شوند. کد زیر نمونه‌ای از این است که چگونه نگه‌داشتن LiveData در Repository می‌تواند رشته اصلی را مسدود کند:

کاتلین

class UserRepository {

    // DON'T DO THIS! LiveData objects should not live in the repository.
    fun getUsers(): LiveData<List<User>> {
        ...
    }

    fun getNewPremiumUsers(): LiveData<List<User>> {
        return getUsers().map { users ->
            // This is an expensive call being made on the main thread and may
            // cause noticeable jank in the UI!
            users
                .filter { user ->
                  user.isPremium
                }
          .filter { user ->
              val lastSyncedTime = dao.getLastSyncedTime()
              user.timeCreated > lastSyncedTime
                }
    }
}

جاوا

class UserRepository {

    // DON'T DO THIS! LiveData objects should not live in the repository.
    LiveData<List<User>> getUsers() {
        ...
    }

    LiveData<List<User>> getNewPremiumUsers() {
    return Transformations.map(getUsers(),
        // This is an expensive call being made on the main thread and may cause
        // noticeable jank in the UI!
        users -> users.stream()
            .filter(User::isPremium)
            .filter(user ->
                user.getTimeCreated() > dao.getLastSyncedTime())
            .collect(Collectors.toList()));
    }
}

اگر لازم است از جریان‌های داده در لایه‌های دیگر برنامه‌تان استفاده کنید، استفاده از Kotlin Flows و سپس تبدیل آن‌ها به LiveData در ViewModel بااستفاده از asLiveData() را مدنظر قرار دهید. در این codelab درباره استفاده از Kotlin Flow با LiveData بیشتر بدانید. برای پایگاه‌های کد ساخته‌شده با Java، استفاده از Executors را در ارتباط با فراخوانی‌های برگشتی یا RxJava درنظر بگیرید.

گسترش LiveData

‫LiveData ناظر را درصورتی در حالت فعال درنظر می‌گیرد که چرخه حیات ناظر در یکی از حالت‌های STARTED یا RESUMED باشد. نمونه کد زیر نحوه گسترش کلاس LiveData را نشان می‌دهد:

کاتلین

class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
    private val stockManager = StockManager(symbol)

    private val listener = { price: BigDecimal ->
        value = price
    }

    override fun onActive() {
        stockManager.requestPriceUpdates(listener)
    }

    override fun onInactive() {
        stockManager.removeUpdates(listener)
    }
}

جاوا

public class StockLiveData extends LiveData<BigDecimal> {
    private StockManager stockManager;

    private SimplePriceListener listener = new SimplePriceListener() {
        @Override
        public void onPriceChanged(BigDecimal price) {
            setValue(price);
        }
    };

    public StockLiveData(String symbol) {
        stockManager = new StockManager(symbol);
    }

    @Override
    protected void onActive() {
        stockManager.requestPriceUpdates(listener);
    }

    @Override
    protected void onInactive() {
        stockManager.removeUpdates(listener);
    }
}

پیاده‌سازی شنونده قیمت در این مثال شامل روش‌های مهم زیر است:

  • وقتی شیء LiveData ناظر فعال داشته باشد، روش onActive() فراخوانی می‌شود. این یعنی باید شروع به مشاهده به‌روزرسانی‌های قیمت سهام از این روش کنید.
  • وقتی شیء LiveData هیچ ناظر فعالی نداشته باشد، روش onInactive() فراخوانی می‌شود. چون هیچ ناظری گوش نمی‌دهد، دلیلی برای متصل ماندن به سرویس StockManager وجود ندارد.
  • روش setValue(T) مقدار نمونه LiveData را به‌روز می‌کند و هرگونه ناظر فعال را از تغییر مطلع می‌کند.

می‌توانید از کلاس StockLiveData به‌صورت زیر استفاده کنید:

کاتلین

public class MyFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val myPriceListener: LiveData<BigDecimal> = ...
        myPriceListener.observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->
            // Update the UI.
        })
    }
}

جاوا

public class MyFragment extends Fragment {
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        LiveData<BigDecimal> myPriceListener = ...;
        myPriceListener.observe(getViewLifecycleOwner(), price -> {
            // Update the UI.
        });
    }
}

روش observe() LifecycleOwner مرتبط با نمای قطعه را به‌عنوان اولین آرگومان ارسال می‌کند. انجام این کار نشان می‌دهد که این ناظر به شیء Lifecycle مرتبط با مالک محدود شده است، یعنی:

  • اگر شیء Lifecycle در حالت فعال نباشد، حتی اگر مقدار تغییر کند، ناظر فراخوانده نمی‌شود.
  • پس‌از نابود شدن شیء Lifecycle، ناظر به‌طور خودکار برداشته می‌شود.

این واقعیت که اشیای LiveData از چرخه حیات آگاه هستند به این معنی است که می‌توانید آن‌ها را بین چندین فعالیت، قطعه، و سرویس هم‌رسانی کنید. برای ساده نگه داشتن مثال، می‌توانید کلاس LiveData را به‌صورت تک‌قلو به‌شرح زیر پیاده‌سازی کنید:

کاتلین

class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
    private val stockManager: StockManager = StockManager(symbol)

    private val listener = { price: BigDecimal ->
        value = price
    }

    override fun onActive() {
        stockManager.requestPriceUpdates(listener)
    }

    override fun onInactive() {
        stockManager.removeUpdates(listener)
    }

    companion object {
        private lateinit var sInstance: StockLiveData

        @MainThread
        fun get(symbol: String): StockLiveData {
            sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
            return sInstance
        }
    }
}

جاوا

public class StockLiveData extends LiveData<BigDecimal> {
    private static StockLiveData sInstance;
    private StockManager stockManager;

    private SimplePriceListener listener = new SimplePriceListener() {
        @Override
        public void onPriceChanged(BigDecimal price) {
            setValue(price);
        }
    };

    @MainThread
    public static StockLiveData get(String symbol) {
        if (sInstance == null) {
            sInstance = new StockLiveData(symbol);
        }
        return sInstance;
    }

    private StockLiveData(String symbol) {
        stockManager = new StockManager(symbol);
    }

    @Override
    protected void onActive() {
        stockManager.requestPriceUpdates(listener);
    }

    @Override
    protected void onInactive() {
        stockManager.removeUpdates(listener);
    }
}

و می‌توانید از آن در قطعه به‌صورت زیر استفاده کنید:

کاتلین

class MyFragment : Fragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->
            // Update the UI.
        })

    }

جاوا

public class MyFragment extends Fragment {
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {
            // Update the UI.
        });
    }
}

چندین قطعه و فعالیت می‌توانند نمونه MyPriceListener را مشاهده کنند. LiveData فقط درصورتی به سرویس سیستم متصل می‌شود که یک یا چند مورد از آن‌ها نمایان و فعال باشد.

تبدیل LiveData

ممکن است بخواهید قبل‌از ارسال شیء LiveData به ناظران، تغییراتی در مقدار ذخیره‌شده در آن ایجاد کنید، یا ممکن است لازم باشد نمونه LiveData متفاوتی را براساس مقدار نمونه دیگری برگردانید. بسته Lifecycle کلاس Transformations را ارائه می‌دهد که شامل روش‌های کمکی است که از این سناریوها پشتیبانی می‌کنند.

Transformations.map()
تابعی را روی مقدار ذخیره‌شده در شیء LiveData اعمال می‌کند و نتیجه را به پایین‌دست منتشر می‌کند.

کاتلین

val userLiveData: LiveData<User> = UserLiveData()
val userName: LiveData<String> = userLiveData.map {
    user -> "${user.name} ${user.lastName}"
}

جاوا

LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
    user.name + " " + user.lastName
});
Transformations.switchMap()
مشابه map()، تابعی را بر مقدار ذخیره‌شده در شیء LiveData اعمال می‌کند و نتیجه را باز می‌کند و به پایین‌دست ارسال می‌کند. تابع ارسال‌شده به switchMap() باید شیء LiveData را برگرداند، همان‌طور که در مثال زیر نشان داده شده است:

کاتلین

private fun getUser(id: String): LiveData<User> {
  ...
}
val userId: LiveData<String> = ...
val user = userId.switchMap { id -> getUser(id) }

جاوا

private LiveData<User> getUser(String id) {
  ...;
}

LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );

می‌توانید از روش‌های تبدیل برای انتقال اطلاعات در سراسر چرخه حیات ناظر استفاده کنید. تبدیل‌ها محاسبه نمی‌شوند مگراینکه ناظری شیء LiveData برگردانده‌شده را تماشا کند. چون تبدیل‌ها به‌صورت تنبل محاسبه می‌شوند، رفتار مرتبط با چرخه حیات به‌طور ضمنی بدون نیاز به فراخوانی‌ها یا وابستگی‌های صریح اضافی منتقل می‌شود.

اگر فکر می‌کنید به شیء Lifecycle در داخل شیء ViewModel نیاز دارید، احتمالاً تبدیل راه‌حل بهتری است. برای مثال، فرض کنید مؤلفه واسط کاربری‌ای دارید که نشانی را می‌پذیرد و کد پستی آن نشانی را برمی‌گرداند. می‌توانید ViewModel ساده را برای این مؤلفه پیاده‌سازی کنید، همان‌طور که در کد نمونه زیر نشان داده شده است:

کاتلین

class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() {

    private fun getPostalCode(address: String): LiveData<String> {
        // DON'T DO THIS
        return repository.getPostCode(address)
    }
}

جاوا

class MyViewModel extends ViewModel {
    private final PostalCodeRepository repository;
    public MyViewModel(PostalCodeRepository repository) {
       this.repository = repository;
    }

    private LiveData<String> getPostalCode(String address) {
       // DON'T DO THIS
       return repository.getPostCode(address);
    }
}

سپس مؤلفه واسط کاربر باید از شیء LiveData قبلی لغو ثبت‌نام کند و هربار که getPostalCode() را فراخوانی می‌کند، در نمونه جدید ثبت‌نام کند. علاوه‌براین، اگر مؤلفه واسط کاربر دوباره ایجاد شود، به‌جای استفاده از نتیجه تماس قبلی، تماس دیگری با روش repository.getPostCode() راه‌اندازی می‌کند.

درعوض، می‌توانید جستجوی کد پستی را به‌عنوان تبدیلی از ورودی نشانی پیاده‌سازی کنید، همان‌طور که در مثال زیر نشان داده شده است:

کاتلین

class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() {
    private val addressInput = MutableLiveData<String>()
    val postalCode: LiveData<String> = addressInput.switchMap {
            address -> repository.getPostCode(address) }


    private fun setInput(address: String) {
        addressInput.value = address
    }
}

جاوا

class MyViewModel extends ViewModel {
    private final PostalCodeRepository repository;
    private final MutableLiveData<String> addressInput = new MutableLiveData();
    public final LiveData<String> postalCode =
            Transformations.switchMap(addressInput, (address) -> {
                return repository.getPostCode(address);
             });

  public MyViewModel(PostalCodeRepository repository) {
      this.repository = repository
  }

  private void setInput(String address) {
      addressInput.setValue(address);
  }
}

در این حالت، فیلد postalCode به‌عنوان تبدیل addressInput تعریف می‌شود. تا زمانی که برنامه‌تان ناظر فعالی داشته باشد که با فیلد postalCode مرتبط باشد، مقدار فیلد هروقت که addressInput تغییر کند دوباره محاسبه و بازیابی می‌شود.

این سازوکار به سطوح پایین‌تر برنامه اجازه می‌دهد اشیای LiveData را ایجاد کند که به‌صورت تنبل و درصورت درخواست محاسبه می‌شوند. شیء ViewModel به‌راحتی می‌تواند ارجاعاتی به اشیاء LiveData دریافت کند و سپس قوانین تبدیل را روی آن‌ها تعریف کند.

ایجاد تبدیل‌های جدید

ده‌ها تبدیل خاص مختلف وجود دارد که ممکن است در برنامه‌تان مفید باشد، اما به‌طور پیش‌فرض ارائه نمی‌شوند. برای پیاده‌سازی تبدیل خودتان می‌توانید از کلاس MediatorLiveData استفاده کنید که به دیگر اشیاء LiveData گوش می‌دهد و رویدادهای منتشرشده توسط آن‌ها را پردازش می‌کند. ‫MediatorLiveData به‌درستی وضعیت خود را به شیء منبع LiveData منتقل می‌کند. برای کسب اطلاعات بیشتر درباره این الگو، به سند مرجع کلاس Transformations مراجعه کنید.

ادغام کردن چند منبع LiveData

MediatorLiveData زیرکلاسی از LiveData است که به شما امکان می‌دهد چندین منبع LiveData را ادغام کنید. سپس ناظران اشیاء MediatorLiveData هرگاه هریک از اشیاء منبع LiveData اصلی تغییر کند، فعال می‌شوند.

برای مثال، اگر شیء LiveData در میانای کاربرتان دارید که می‌تواند از پایگاه داده محلی یا شبکه به‌روز شود، می‌توانید منابع زیر را به شیء MediatorLiveData اضافه کنید:

  • یک شیء LiveData مرتبط با داده‌های ذخیره‌شده در پایگاه داده.
  • شیء LiveData مرتبط با داده‌های دسترسی‌یافته از شبکه.

فعالیت شما فقط باید شیء MediatorLiveData را مشاهده کند تا به‌روزرسانی‌ها را از هر دو منبع دریافت کند. برای مشاهده مثالی دقیق، به بخش ضمیمه: افشای وضعیت شبکه در راهنمای معماری برنامه مراجعه کنید.

منابع بیشتر

برای کسب اطلاعات بیشتر درباره کلاس LiveData، به منابع زیر مراجعه کنید.

نمونه‌ها

  • Sunflower، برنامه نمایشی که روال‌های مطلوب را با Architecture Components نشان می‌دهد

Codelabs

وبلاگ‌ها

ویدیوها