LiveData के बारे में खास जानकारी   यह Android Jetpack का हिस्सा है.

LiveData, डेटा होल्डर की ऐसी क्लास है जिसे ऑब्ज़र्व किया जा सकता है. सामान्य ऑब्ज़र्वेबल के मुकाबले, LiveData लाइफ़साइकल के बारे में जानकारी रखता है. इसका मतलब है कि यह ऐप्लिकेशन के अन्य कॉम्पोनेंट के लाइफ़साइकल का ध्यान रखता है. जैसे, ऐक्टिविटी, फ़्रैगमेंट या सेवाएं. इस जानकारी से यह पक्का होता है कि LiveData सिर्फ़ उन ऐप्लिकेशन कॉम्पोनेंट ऑब्ज़र्वर को अपडेट करता है जो लाइफ़साइकल की चालू स्थिति में हैं.

LiveData, किसी ऑब्ज़र्वर को चालू स्थिति में तब मानता है, जब उसका लाइफ़साइकल STARTED या RESUMED स्थिति में हो. ऑब्ज़र्वर को Observer क्लास से दिखाया जाता है. 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. observe() तरीके का इस्तेमाल करके, Observer ऑब्जेक्ट को LiveData ऑब्जेक्ट से अटैच करें. observe() का तरीका, LifecycleOwner ऑब्जेक्ट लेता है. इससे Observer ऑब्जेक्ट, LiveData ऑब्जेक्ट की सदस्यता ले लेता है, ताकि उसे बदलावों की सूचना मिल सके. आम तौर पर, Observer ऑब्जेक्ट को किसी यूज़र इंटरफ़ेस (यूआई) कंट्रोलर में अटैच किया जाता है, जैसे कि ऐक्टिविटी या फ़्रैगमेंट.

LiveData ऑब्जेक्ट में सेव की गई वैल्यू को अपडेट करने पर, यह सभी रजिस्टर किए गए ऑब्ज़र्वर को ट्रिगर करता है. ऐसा तब तक होता है, जब तक अटैच किया गया LifecycleOwner चालू रहता है.

LiveData की मदद से, यूज़र इंटरफ़ेस (यूआई) कंट्रोलर के ऑब्ज़र्वर, अपडेट की सदस्यता ले सकते हैं. जब LiveData ऑब्जेक्ट में मौजूद डेटा बदलता है, तो यूज़र इंटरफ़ेस (यूआई) अपने-आप अपडेट हो जाता है.

LiveData ऑब्जेक्ट बनाना

LiveData एक रैपर है, जिसका इस्तेमाल किसी भी डेटा के साथ किया जा सकता है. इसमें List जैसे Collections को लागू करने वाले ऑब्जेक्ट भी शामिल हैं. आम तौर पर, LiveData ऑब्जेक्ट को ViewModel ऑब्जेक्ट में सेव किया जाता है. साथ ही, इसे किसी गेट्टर तरीके से ऐक्सेस किया जाता है. इसका उदाहरण यहां दिया गया है:

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 ऑब्जेक्ट को मॉनिटर करना शुरू करना सही होता है. ऐसा इन वजहों से किया जाता है:

  • यह पक्का करने के लिए कि सिस्टम किसी ऐक्टिविटी या फ़्रैगमेंट के 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);
    }
}

nameObserver को पैरामीटर के तौर पर पास करके, observe() को कॉल करने के बाद, mCurrentName में सेव की गई सबसे हाल की वैल्यू देने के लिए, onChanged() को तुरंत लागू किया जाता है. अगर 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) को कॉल करने पर, ऑब्ज़र्वर John Doe वैल्यू के साथ अपने onChanged() तरीकों को कॉल करते हैं. उदाहरण में बटन दबाने की जानकारी दी गई है, लेकिन mName को अपडेट करने के लिए setValue() या postValue() को कई वजहों से कॉल किया जा सकता है. जैसे, नेटवर्क अनुरोध या डेटाबेस लोड होने के बाद. सभी मामलों में, setValue() या postValue() को कॉल करने पर, ऑब्ज़र्वर ट्रिगर होते हैं और यूज़र इंटरफ़ेस (यूआई) अपडेट होता है.

Room के साथ LiveData का इस्तेमाल करना

Room परसिस्टेंस लाइब्रेरी, ऑब्ज़र्व की जा सकने वाली क्वेरी के साथ काम करती है. ये क्वेरी, LiveData ऑब्जेक्ट दिखाती हैं. ऑब्ज़र्वेबल क्वेरी, डेटाबेस ऐक्सेस ऑब्जेक्ट (डीएओ) के हिस्से के तौर पर लिखी जाती हैं.

डेटाबेस अपडेट होने पर, Room LiveData ऑब्जेक्ट को अपडेट करने के लिए ज़रूरी कोड जनरेट करता है. जनरेट किया गया कोड, ज़रूरत पड़ने पर बैकग्राउंड थ्रेड पर एसिंक्रोनस तरीके से क्वेरी चलाता है. यह पैटर्न, यूज़र इंटरफ़ेस (यूआई) में दिखाए गए डेटा को डेटाबेस में सेव किए गए डेटा के साथ सिंक रखने के लिए मददगार होता है. रूम परसिस्टेंट लाइब्रेरी की गाइड में, Room और डीएओ के बारे में ज़्यादा पढ़ा जा सकता है.

LiveData के साथ कोरूटीन का इस्तेमाल करना

LiveData में Kotlin कोरूटीन के लिए सहायता शामिल है. ज़्यादा जानकारी के लिए, Android आर्किटेक्चर कॉम्पोनेंट के साथ Kotlin कोरूटीन इस्तेमाल करना लेख पढ़ें.

ऐप्लिकेशन के आर्किटेक्चर में LiveData

LiveData, लाइफ़साइकल की जानकारी रखता है. यह ऐक्टिविटी और फ़्रैगमेंट जैसी इकाइयों की लाइफ़साइकल को फ़ॉलो करता है. लाइफ़साइकल के मालिकों और ViewModel ऑब्जेक्ट जैसे अन्य ऑब्जेक्ट के बीच कम्यूनिकेट करने के लिए, LiveData का इस्तेमाल करें. ViewModel की मुख्य ज़िम्मेदारी, यूज़र इंटरफ़ेस (यूआई) से जुड़े डेटा को लोड और मैनेज करना है. इस वजह से, यह LiveData ऑब्जेक्ट को होल्ड करने के लिए एक बेहतरीन विकल्प है. ViewModel में LiveData ऑब्जेक्ट बनाएं और उनका इस्तेमाल करके, यूज़र इंटरफ़ेस (यूआई) लेयर में स्टेटस दिखाएं.

गतिविधियों और फ़्रैगमेंट में LiveData इंस्टेंस नहीं होने चाहिए, क्योंकि उनकी भूमिका डेटा दिखाने की है, न कि स्थिति दिखाने की. साथ ही, ऐक्टिविटी और फ़्रैगमेंट में डेटा सेव न करने से, यूनिट टेस्ट लिखना आसान हो जाता है.

ऐसा हो सकता है कि आपको अपनी डेटा लेयर क्लास में LiveData ऑब्जेक्ट इस्तेमाल करने का मन करे, लेकिन LiveData को डेटा की असाइनोक्रोनस स्ट्रीम को हैंडल करने के लिए डिज़ाइन नहीं किया गया है. हालांकि, ऐसा करने के लिए LiveData ट्रांसफ़ॉर्मेशन और MediatorLiveData का इस्तेमाल किया जा सकता है, लेकिन इस तरीके में कुछ समस्याएं हैं: डेटा स्ट्रीम को आपस में जोड़ने की सुविधा काफ़ी सीमित है. साथ ही, सभी LiveData ऑब्जेक्ट (इनमें ट्रांसफ़ॉर्मेशन की मदद से बनाए गए ऑब्जेक्ट भी शामिल हैं) को मुख्य थ्रेड पर देखा जाता है. नीचे दिए गए कोड में बताया गया है कि Repository में LiveData को होल्ड करने से मुख्य थ्रेड कैसे ब्लॉक हो सकता है:

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 फ़्लो का इस्तेमाल करें. इसके बाद, asLiveData() का इस्तेमाल करके, उन्हें ViewModel में LiveData में बदलें. इस कोडलैब में, Kotlin Flow को LiveData के साथ इस्तेमाल करने के बारे में ज़्यादा जानें. Java से बनाए गए कोडबेस के लिए, कॉलबैक या 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 क्लास को सिंगलटन के तौर पर इस तरह लागू किया जा सकता है:

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 ऑब्जेक्ट को देख रहा हो. ट्रांसफ़ॉर्मेशन का हिसाब, धीरे-धीरे लगाया जाता है. इसलिए, लाइफ़साइकल से जुड़ा व्यवहार, साफ़ तौर पर कॉल या डिपेंडेंसी के बिना, अपने-आप पास किया जाता है.

अगर आपको लगता है कि आपको ViewModel ऑब्जेक्ट के अंदर Lifecycle ऑब्जेक्ट की ज़रूरत है, तो ट्रांसफ़ॉर्मेशन एक बेहतर समाधान हो सकता है. उदाहरण के लिए, मान लें कि आपके पास एक यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट है, जो कोई पता स्वीकार करता है और उस पते का पिन कोड दिखाता है. इस कॉम्पोनेंट के लिए, नॉन-एलिमेंट 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() को कॉल करने पर, नए इंस्टेंस पर रजिस्टर करना होगा. इसके अलावा, अगर यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट को फिर से बनाया जाता है, तो यह पिछले कॉल के नतीजे का इस्तेमाल करने के बजाय, 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 ऑब्जेक्ट के रेफ़रंस आसानी से पा सकता है. इसके बाद, उन पर ट्रांसफ़ॉर्मेशन के नियम तय कर सकता है.

नए ट्रांसफ़ॉर्मेशन बनाना

आपके ऐप्लिकेशन में, 12 अलग-अलग ट्रांसफ़ॉर्मेशन फ़ंक्शन काम के हो सकते हैं. हालांकि, ये डिफ़ॉल्ट रूप से उपलब्ध नहीं होते. अपने हिसाब से बदलाव करने के लिए, MediatorLiveData क्लास का इस्तेमाल किया जा सकता है. यह क्लास, दूसरे LiveData ऑब्जेक्ट को सुनती है और उनसे मिलने वाले इवेंट को प्रोसेस करती है. MediatorLiveData, सोर्स LiveData ऑब्जेक्ट में अपनी स्थिति को सही तरीके से भेजता है. इस पैटर्न के बारे में ज़्यादा जानने के लिए, Transformations क्लास का रेफ़रंस दस्तावेज़ देखें.

एक से ज़्यादा LiveData सोर्स को मर्ज करना

MediatorLiveData, LiveData का एक सबक्लास है. इसकी मदद से, एक से ज़्यादा LiveData सोर्स को मर्ज किया जा सकता है. जब भी किसी ओरिजनल LiveData सोर्स ऑब्जेक्ट में बदलाव होता है, तो MediatorLiveData ऑब्जेक्ट के ऑब्ज़र्वर ट्रिगर हो जाते हैं.

उदाहरण के लिए, अगर आपके यूज़र इंटरफ़ेस (यूआई) में कोई ऐसा LiveData ऑब्जेक्ट है जिसे किसी स्थानीय डेटाबेस या नेटवर्क से अपडेट किया जा सकता है, तो MediatorLiveData ऑब्जेक्ट में ये सोर्स जोड़े जा सकते हैं:

  • डेटाबेस में सेव किए गए डेटा से जुड़ा LiveData ऑब्जेक्ट.
  • नेटवर्क से ऐक्सेस किए गए डेटा से जुड़ा LiveData ऑब्जेक्ट.

दोनों सोर्स से अपडेट पाने के लिए, आपकी गतिविधि को सिर्फ़ MediatorLiveData ऑब्जेक्ट को मॉनिटर करना होगा. ज़्यादा जानकारी के लिए, ऐप्लिकेशन के आर्किटेक्चर से जुड़ी गाइड में अतिरिक्त जानकारी: नेटवर्क की स्थिति दिखाना सेक्शन देखें.

अन्य संसाधन

LiveData क्लास के बारे में ज़्यादा जानने के लिए, यहां दिए गए रिसॉर्स देखें.

सैंपल

  • Sunflower, एक डेमो ऐप्लिकेशन है. इसमें, आर्किटेक्चर कॉम्पोनेंट के साथ काम करने के सबसे सही तरीके दिखाए गए हैं

कोडलैब

ब्लॉग

वीडियो