סקירה כללית על LiveData   חלק מ-Android Jetpack.

LiveData היא סוג של מחזיק נתונים שניתן לצפות בו. בניגוד למשתנה רגיל שניתן לצפות בו, משתנה LiveData מודע למחזור החיים, כלומר הוא מתייחס למחזור החיים של רכיבים אחרים באפליקציה, כמו פעילויות, קטעים או שירותים. כך מוודאים ש-LiveData מעדכן רק משגיחים על רכיבי האפליקציה שנמצאים במצב פעיל במחזור החיים.

ב-LiveData, משתמש שמתבונן (observer) שמיוצג על ידי הכיתה Observer נחשב כפעיל אם מחזור החיים שלו נמצא בסטטוס STARTED או בסטטוס RESUMED. LiveData מעדכן רק משתמשים פעילים על עדכונים. משתמשים לא פעילים שנרשמו למעקב אחרי אובייקטים מסוג LiveData לא יקבלו התראות על שינויים.

אפשר לרשום משתמש שמתבונן (observer) עם אובייקט שמטמיע את הממשק LifecycleOwner. הקשר הזה מאפשר להסיר את הצופה כשהסטטוס של האובייקט התואם Lifecycle משתנה ל-DESTROYED. האפשרות הזו שימושית במיוחד לפעילויות ולקטעים, כי הם יכולים לצפות בעצמם באובייקטים מסוג LiveData בלי לדאוג לדליפות – הפעילויות והקטעים מבטלים את ההרשמה באופן מיידי כשמחסלים את מחזורי החיים שלהם.

מידע נוסף על השימוש ב-LiveData זמין במאמר עבודה עם אובייקטים של LiveData.

היתרונות של השימוש ב-LiveData

היתרונות של שימוש ב-LiveData:

מוודאים שממשק המשתמש תואם למצב הנתונים
LiveData פועל לפי תבנית הצופה. כשהנתונים הבסיסיים משתנים, LiveData מעדכנת את האובייקטים מסוג Observer. אפשר לאחד את הקוד כדי לעדכן את ממשק המשתמש באובייקטים האלה של Observer. כך לא תצטרכו לעדכן את ממשק המשתמש בכל פעם שנתוני האפליקציה משתנים, כי הצופה יעשה זאת בשבילכם.
ללא דליפות זיכרון
המעקבים מקושרים לאובייקטים מסוג Lifecycle, ומבצעים ניקוי אחרי עצמם כשמחזור החיים המשויך להם נהרס.
אין קריסות בגלל פעילויות שהופסקו
אם מחזור החיים של הצופה לא פעיל, למשל במקרה של פעילות ב-back stack, הוא לא מקבל אירועי LiveData.
אין יותר ניהול ידני של מחזור החיים
רכיבי ממשק המשתמש רק צופים בנתונים הרלוונטיים ולא מפסיקים או ממשיכים את המעקב. LiveData מנהלת את כל זה באופן אוטומטי, כי היא מודעת לשינויים הרלוונטיים בסטטוס מחזור החיים במהלך המעקב.
נתונים תמיד עדכניים
אם מחזור חיים הופך ללא פעיל, הוא מקבל את הנתונים העדכניים כשהוא הופך שוב לפעיל. לדוגמה, פעילות שהיתה ברקע מקבלת את הנתונים העדכניים מיד אחרי שהיא חוזרת לחזית.
שינויים מתאימים בהגדרות
אם פעילות או קטע נוצרים מחדש בגלל שינוי בהגדרות, כמו רוטציה של המכשיר, הם מקבלים מיד את הנתונים העדכניים ביותר שזמינים.
שיתוף משאבים
אפשר להרחיב אובייקט LiveData באמצעות תבנית ה-singleton כדי לעטוף שירותי מערכת, כך שאפשר יהיה לשתף אותם באפליקציה. אובייקט LiveData מתחבר לשירות המערכת פעם אחת, ואז כל משתמש שזקוק למשאב יכול פשוט לצפות באובייקט LiveData. מידע נוסף זמין במאמר הרחבת LiveData.

עבודה עם אובייקטים של LiveData

כדי לעבוד עם אובייקטים מסוג LiveData:

  1. יצירת מופע של LiveData לאחסון סוג מסוים של נתונים. בדרך כלל עושים זאת בכיתה ViewModel.
  2. יוצרים אובייקט Observer שמגדיר את השיטה onChanged(), שמאפשרת לקבוע מה יקרה כשהנתונים שמאוחסנים באובייקט LiveData ישתנו. בדרך כלל יוצרים אובייקט Observer בבורר של ממשק המשתמש, כמו פעילות או קטע.
  3. מחברים את האובייקט Observer לאובייקט LiveData באמצעות השיטה observe(). השיטה observe() מקבלת אובייקט LifecycleOwner. הפעולה הזו מביאה להרשמה של האובייקט Observer לאובייקט LiveData, כדי שיקבל התראות על שינויים. בדרך כלל מחברים את האובייקט Observer למסוף UI, כמו פעילות או קטע.

כשמעדכנים את הערך שנשמר באובייקט LiveData, הוא מפעיל את כל המשקיפים הרשומים כל עוד ה-LifecycleOwner המצורף נמצא במצב פעיל.

LiveData מאפשרת למשתמשי UI controller להירשם לעדכונים. כשהנתונים שמאוחסנים באובייקט LiveData משתנים, ממשק המשתמש מתעדכן באופן אוטומטי בתגובה.

יצירת אובייקטים של LiveData

‏LiveData הוא מעטפת שאפשר להשתמש בה עם כל נתונים, כולל אובייקטים שמטמיעים את Collections, כמו List. אובייקט LiveData מאוחסן בדרך כלל בתוך אובייקט ViewModel, והגישה אליו מתבצעת באמצעות method של getter, כפי שמתואר בדוגמה הבאה:

Kotlin

class NameViewModel : ViewModel() {

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

    // Rest of the ViewModel...
}

Java

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, מהסיבות הבאות:

  • כדי לוודא שהמערכת לא מבצעת קריאות מיותרות מה-method‏ onResume() של פעילות או של קטע.
  • כדי לוודא שלפעילות או לקטע יש נתונים שאפשר להציג ברגע שהם הופכים לפעילים. ברגע שרכיב באפליקציה נמצא בסטטוס STARTED, הוא מקבל את הערך העדכני ביותר מהאובייקטים מסוג LiveData שהוא עוקב אחריהם. זה קורה רק אם אובייקט LiveData שרוצים לעקוב אחריו הוגדר.

בדרך כלל, LiveData מעביר עדכונים רק כשהנתונים משתנים, ורק למשתמשי מעקב פעילים. חריג להתנהגות הזו הוא שגם משתמשים צופים מקבלים עדכון כשהם עוברים מסטטוס לא פעיל לסטטוס פעיל. בנוסף, אם המשתנה של הצופה עובר מ'לא פעיל' ל'פעיל' בפעם השנייה, הוא מקבל עדכון רק אם הערך השתנה מאז הפעם האחרונה שהוא הפך לפעיל.

דוגמת הקוד הבאה מראה איך מתחילים לעקוב אחרי אובייקט LiveData:

Kotlin

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)
    }
}

Java

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, כפי שמתואר בדוגמה הבאה, שמפעילה את כל הצופים כשהמשתמש מקשיב על לחצן:

Kotlin

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

Java

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.

שימוש ב-coroutines עם LiveData

LiveData כולל תמיכה ב-coroutines של Kotlin. למידע נוסף, ראו שימוש ב-coroutines של Kotlin עם רכיבי הארכיטקטורה של Android.

שימוש ב-LiveData בארכיטקטורה של אפליקציה

LiveData מודע למחזור החיים, ועוקב אחרי מחזור החיים של ישויות כמו פעילויות ופרטי מידע. משתמשים ב-LiveData כדי לתקשר בין בעלי מחזור החיים האלה לבין אובייקטים אחרים עם משך חיים שונה, כמו אובייקטים מסוג ViewModel. התפקיד העיקרי של ViewModel הוא לטעון ולנהל נתונים שקשורים לממשק המשתמש, ולכן הוא מתאים מאוד לאחסון אובייקטים מסוג LiveData. יוצרים אובייקטים מסוג LiveData ב-ViewModel ומשתמשים בהם כדי לחשוף את המצב לשכבת ממשק המשתמש.

אסור לאחסן בפעילויות ובקטעים עותקים של LiveData, כי התפקיד שלהם הוא להציג נתונים, ולא לאחסן מצב. בנוסף, כשפעילות ופרפאג'טים לא שומרים נתונים, קל יותר לכתוב בדיקות יחידה.

יכול להיות שתתפתתו לעבוד עם אובייקטים מסוג LiveData בכיתה של שכבת הנתונים, אבל LiveData לא תוכנן לטיפול בזרמים אסינכרונים של נתונים. אפשר להשתמש בטרנספורמציות של LiveData וב-MediatorLiveData כדי להשיג את זה, אבל יש לשיטה הזו חסרונות: היכולת לשלב בין מקורות נתונים מוגבלת מאוד וכל האובייקטים מסוג LiveData (כולל אלה שנוצרו באמצעות טרנספורמציות) נצפים בשרשור הראשי. הקוד שבהמשך הוא דוגמה לאופן שבו החזקה של LiveData ב-Repository יכולה לחסום את הליבה:

Kotlin

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
                }
    }
}

Java

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(). בקודלאב הזה מוסבר איך משתמשים ב-Kotlin Flow עם LiveData. בקוד בסיס שנוצר ב-Java, מומלץ להשתמש ב-Executors בשילוב עם פונקציות קריאה חוזרת או RxJava.

הרחבת LiveData

מערכת LiveData מתייחסת למשתמש שמתבונן כפעיל אם מחזור החיים שלו נמצא באחד מהמצבים STARTED או RESUMED. הקוד לדוגמה הבא מראה איך להרחיב את הכיתה LiveData:

Kotlin

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)
    }
}

Java

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);
    }
}

ההטמעה של מאזין המחירים בדוגמה הזו כוללת את השיטות החשובות הבאות:

  • השיטה onActive() נקראת כשיש למשתנה LiveData משתמש פעיל. כלומר, צריך להתחיל לעקוב אחרי עדכוני מחירי המניות באמצעות השיטה הזו.
  • השיטה onInactive() נקראת כשלאובייקט LiveData אין משקיפים פעילים. מכיוון שאין משתמשים נוספים שמאזינים, אין סיבה להישאר מחוברים לשירות StockManager.
  • השיטה setValue(T) מעדכנת את הערך של מופע LiveData ומודיעה על השינוי לכל המשקיפים הפעילים.

אפשר להשתמש בכיתה StockLiveData באופן הבא:

Kotlin

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.
        })
    }
}

Java

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 כ-singleton באופן הבא:

Kotlin

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
        }
    }
}

Java

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);
    }
}

אפשר להשתמש בו בקוד הבא:

Kotlin

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.
        })

    }

Java

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 ומפיצה את התוצאה במורד הזרם.

Kotlin

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

Java

LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
    user.name + " " + user.lastName
});
Transformations.switchMap()
בדומה ל-map(), מחילה פונקציה על הערך שמאוחסן באובייקט LiveData, פותחת את האריזה של התוצאה ושולחת אותה במורד הזרם. הפונקציה שמעבירים ל-switchMap() חייבת להחזיר אובייקט LiveData, כפי שמתואר בדוגמה הבאה:

Kotlin

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

Java

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

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

אפשר להשתמש בשיטות טרנספורמציה כדי לשאת מידע במהלך מחזור החיים של הצופה. הטרנספורמציות לא מחושבות אלא אם משתמש צופה באובייקט LiveData המוחזר. מאחר שהטרנספורמציות מחושבות באופן עצל, ההתנהגות שקשורה למחזור החיים מועברת באופן משתמע בלי צורך בקריאות או בתלות נוספות באופן מפורש.

אם אתם חושבים שאתם צריכים אובייקט Lifecycle בתוך אובייקט ViewModel, כנראה שתהליך טרנספורמציה הוא פתרון טוב יותר. לדוגמה, נניח שיש לכם רכיב UI שמקבל כתובת ומחזיר את המיקוד של אותה כתובת. אפשר להטמיע את ViewModel הפשוט לרכיב הזה, כפי שמתואר בדוגמת הקוד הבאה:

Kotlin

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

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

Java

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(). בנוסף, אם רכיב ממשק המשתמש נוצר מחדש, הוא מפעיל קריאה נוספת ל-method‏ repository.getPostCode() במקום להשתמש בתוצאה של הקריאה הקודמת.

במקום זאת, אפשר להטמיע את בדיקת המיקוד כטרנספורמציה של קלט הכתובת, כפי שמוצג בדוגמה הבאה:

Kotlin

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
    }
}

Java

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, אפליקציית הדגמה שממחישה שיטות מומלצות לשימוש ברכיבי ארכיטקטורה

Codelabs

בלוגים

סרטונים