ViewModel की खास जानकारी, जो Android Jetpack का हिस्सा है.

Kotlin Multiplatform के साथ आज़माएं
Kotlin Multiplatform की मदद से, कारोबारी नियम को अन्य प्लैटफ़ॉर्म के साथ शेयर किया जा सकता है. केएमपी में ViewModel को सेट अप करने और उसके साथ काम करने का तरीका जानें

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

स्टेट होल्डर के बारे में ज़्यादा जानने के लिए, स्टेट होल्डर के दिशा-निर्देश देखें. इसी तरह, यूज़र इंटरफ़ेस (यूआई) लेयर के बारे में ज़्यादा जानने के लिए, यूज़र इंटरफ़ेस (यूआई) लेयर दिशा-निर्देश देखें.

ViewModel के फ़ायदे

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

इसके अलावा, सिर्फ़ स्टेट होल्डर के लिए, Compose में retain की सुविधाएं उपलब्ध हैं. इनकी मदद से, सामान्य क्लास, ViewModel के पूरे इन्फ़्रास्ट्रक्चर के बिना भी कॉन्फ़िगरेशन में बदलाव होने पर भी काम कर सकती हैं. हालांकि, दोनों मैकेनिज़्म, स्टेट को बनाए रखने में मदद करते हैं. आम तौर पर, रिटेन किए गए इंस्टेंस को ViewModel देना ज़्यादा सुरक्षित होता है. ऐसा इसलिए, क्योंकि इनकी लाइफ़साइकल और क्लीनअप के तरीके अलग-अलग होते हैं.

ViewModel क्लास के मुख्य तौर पर दो फ़ायदे हैं:

  • इससे यूज़र इंटरफ़ेस (यूआई) की स्टेट को बनाए रखा जा सकता है.
  • इससे कारोबारी नियम का ऐक्सेस मिलता है.

स्थायी

ViewModel, स्टेट और कार्रवाइयों, दोनों को बनाए रखता है. स्टेट, ViewModel में सेव रहता है और कार्रवाइयां, ViewModel ट्रिगर करता है. कैश करने का मतलब है कि आपको स्क्रीन रोटेट करने जैसे सामान्य कॉन्फ़िगरेशन में बदलाव होने पर, डेटा फिर से फ़ेच नहीं करना पड़ता.

दायरा

ViewModel को इंस्टैंशिएट करते समय, उसे ViewModelStoreOwner इंटरफ़ेस लागू करने वाला ऑब्जेक्ट पास किया जाता है. यह नेविगेशन डेस्टिनेशन, नेविगेशन ग्राफ़, ऐक्टिविटी या इंटरफ़ेस लागू करने वाला कोई अन्य टाइप हो सकता है. एपीआई का इस्तेमाल करके, ViewModel को सीधे तौर पर कंपोज़ेबल के दायरे में भी रखा जा सकता है.rememberViewModelStoreOwner इसके बाद, आपका ViewModel, लाइफ़साइकल के दायरे में आ जाता है ViewModelStoreOwner. यह तब तक मेमोरी में सेव रहता है, जब तक इसका ViewModelStoreOwner हमेशा के लिए मिट नहीं जाता. जैसे, कंपोज़ेबल का मालिक कंपोज़िशन से बाहर निकल जाता है.

कई क्लास, ViewModelStoreOwner इंटरफ़ेस की डायरेक्ट या इनडायरेक्ट सबक्लास होती हैं. डायरेक्ट सबक्लास, ComponentActivity और NavBackStackEntry हैं. इनडायरेक्ट सबक्लास की पूरी सूची के लिए, ViewModelStoreOwner रेफ़रंस देखें. LazyList या Pager में मौजूद अलग-अलग आइटम के लिए, ViewModels को दायरे में रखने के लिए, rememberViewModelStoreProvider() का इस्तेमाल करें, ताकि मालिक के मैनेजमेंट को पैरंट तक पहुंचाया जा सके.

जब होस्ट ऐक्टिविटी में कॉन्फ़िगरेशन में बदलाव होता है, तब ViewModel में एसिंक्रोनस काम जारी रहता है. भले ही, वह ऐक्टिविटी या किसी खास कंपोज़ेबल के दायरे में हो. यह परसिस्टेंस की मुख्य वजह है.

ज़्यादा जानकारी के लिए, ViewModel की लाइफ़साइकल वाला सेक्शन, ViewModel स्कोपिंग एपीआई, और Jetpack Compose के लिए स्टेट होइस्टिंग की गाइड देखें.

SavedStateHandle

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

यूज़र इंटरफ़ेस (यूआई) की स्टेट को सेव करने के बारे में ज़्यादा जानने के लिए, Compose में यूज़र इंटरफ़ेस (यूआई) की स्टेट सेव करना देखें.

कारोबारी नियम का ऐक्सेस

ज़्यादातर कारोबारी नियम, डेटा लेयर में मौजूद होते हैं. हालांकि, यूज़र इंटरफ़ेस (यूआई) लेयर में भी कारोबारी नियम हो सकते हैं. ऐसा तब हो सकता है, जब स्क्रीन के यूज़र इंटरफ़ेस (यूआई) की स्टेट बनाने के लिए, कई रिपॉज़िटरी से डेटा को जोड़ा जाता है या जब किसी खास तरह के डेटा के लिए, डेटा लेयर की ज़रूरत नहीं होती.

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

ViewModel लागू करना

यहां, ऐसी स्क्रीन के लिए ViewModel लागू करने का उदाहरण दिया गया है जिससे उपयोगकर्ता पासा रोल कर सकता है.

data class DiceUiState(
    val firstDieValue: Int? = null,
    val secondDieValue: Int? = null,
    val numberOfRolls: Int = 0,
)

class DiceRollViewModel : ViewModel() {

    // Expose screen UI state
    private val _uiState = MutableStateFlow(DiceUiState())
    val uiState: StateFlow<DiceUiState> = _uiState.asStateFlow()

    // Handle business logic
    fun rollDice() {
        _uiState.update { currentState ->
            currentState.copy(
                firstDieValue = Random.nextInt(from = 1, until = 7),
                secondDieValue = Random.nextInt(from = 1, until = 7),
                numberOfRolls = currentState.numberOfRolls + 1,
            )
        }
    }
}

इसके बाद, स्क्रीन-लेवल के कंपोज़ेबल से ViewModel को इस तरह ऐक्सेस किया जा सकता है:

import androidx.lifecycle.viewmodel.compose.viewModel

// Use the 'viewModel()' function from the lifecycle-viewmodel-compose artifact
@Composable
fun DiceRollScreen(
    viewModel: DiceRollViewModel = viewModel()
) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()
    // Update UI elements
}

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

ViewModel में, Kotlin कोरूटीन के लिए सहायता शामिल है. यह एसिंक्रोनस काम को उसी तरह बनाए रख सकता है जिस तरह यूज़र इंटरफ़ेस (यूआई) की स्टेट को बनाए रखता है.

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

ViewModel की लाइफ़साइकल

The lifecycle of a ViewModel की लाइफ़साइकल, सीधे तौर पर इसके स्कोप से जुड़ी होती है. A ViewModel तब तक मेमोरी में सेव रहता है, जब तक वह ViewModelStoreOwner गायब नहीं हो जाता जिसके दायरे में वह होता है. ऐसा इन स्थितियों में हो सकता है:

  • ऐक्टिविटी के खत्म होने पर.
  • नेविगेशन एंट्री के बैक स्टैक से हटाए जाने पर.
  • कंपोज़ेबल के कंपोज़िशन से बाहर निकलने पर. rememberViewModelStoreOwner का इस्तेमाल करके, ViewModel को सीधे तौर पर अपने यूज़र इंटरफ़ेस (यूआई) के किसी भी हिस्से (जैसे, Pager या LazyList) के दायरे में रखा जा सकता है.

इससे ViewModels, कॉन्फ़िगरेशन में बदलाव होने पर भी डेटा को सेव करने का एक बेहतरीन तरीका बन जाता है.

पहली इमेज में, किसी ऐक्टिविटी की अलग-अलग लाइफ़साइकल स्टेट दिखाई गई हैं. इसमें दिखाया गया है कि ऐक्टिविटी को रोटेट करने और फिर खत्म करने पर, उसकी लाइफ़साइकल स्टेट में क्या बदलाव होते हैं. इस इमेज में, उससे जुड़ी ऐक्टिविटी की लाइफ़साइकल के बगल में ViewModel की लाइफ़साइकल भी दिखाई गई है. इस डायग्राम में, किसी ऐक्टिविटी की स्टेट दिखाई गई हैं.

इस इमेज में, ऐक्टिविटी की स्थिति बदलने पर ViewModel की लाइफ़साइकल को दिखाया गया है.
पहली इमेज. किसी ऐक्टिविटी और ViewModel की लाइफ़साइकल स्टेट.

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

ViewModel की डिपेंडेंसी साफ़ करना

ViewModel, onCleared तरीके को तब कॉल करता है, जब ViewModelStoreOwner अपनी लाइफ़साइकल के दौरान इसे डिस्ट्रॉय करता है. इससे, ViewModel की लाइफ़साइकल के दौरान किए गए किसी भी काम या डिपेंडेंसी को साफ़ किया जा सकता है.

यहां, viewModelScope के विकल्प का उदाहरण दिया गया है. viewModelScope एक बिल्ट-इन CoroutineScope है, जो ViewModel की लाइफ़साइकल को अपने-आप फ़ॉलो करता है. ViewModel, कारोबारी नियम से जुड़ी कार्रवाइयों को ट्रिगर करने के लिए इसका इस्तेमाल करता है. अगर आपको आसान टेस्टिंग के लिए, viewModelScope के बजाय कोई कस्टम स्कोप इस्तेमाल करना है, तो ViewModel, अपने कंस्ट्रक्टर में CoroutineScope को डिपेंडेंसी के तौर पर पा सकता है. जब ViewModelStoreOwner, ViewModel को उसकी लाइफ़साइकल के आखिर में साफ़ करता है, तब ViewModel, CoroutineScope को भी रद्द कर देता है.

class MyViewModel(
    private val coroutineScope: CoroutineScope =
        CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
) : ViewModel() {

    // Other ViewModel logic ...

    override fun onCleared() {
        coroutineScope.cancel()
    }
}

लाइफ़साइकल के वर्शन 2.5 और इसके बाद वाले वर्शन में, ViewModel के कंस्ट्रक्टर को एक या उससे ज़्यादा Closeable ऑब्जेक्ट पास किए जा सकते हैं. ViewModel इंस्टेंस के साफ़ होने पर, ये ऑब्जेक्ट अपने-आप बंद हो जाते हैं.

class CloseableCoroutineScope(
    context: CoroutineContext = SupervisorJob() + Dispatchers.Main.immediate
) : Closeable, CoroutineScope {
    override val coroutineContext: CoroutineContext = context
    override fun close() {
        coroutineContext.cancel()
   }
}

class MyViewModel(
    private val coroutineScope: CoroutineScope = CloseableCoroutineScope()
) : ViewModel(coroutineScope) {
    // Other ViewModel logic ...
}

सबसे सही तरीके

ViewModel लागू करते समय, यहां दिए गए कुछ मुख्य सबसे सही तरीकों का पालन करें:

  • ViewModel को स्क्रीन लेवल के स्टेट होल्डर के लागू करने के तरीके के तौर पर इस्तेमाल करें. ऐसा इसलिए, क्योंकि ये स्कोप किए जा सकते हैं. इन्हें, फिर से इस्तेमाल किए जा सकने वाले यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट के स्टेट होल्डर के तौर पर इस्तेमाल न करें. जैसे, चिप ग्रुप या फ़ॉर्म. ऐसा न करने पर, आपको एक ही ViewModelStoreOwner के तहत, एक ही यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट के अलग-अलग इस्तेमाल में, एक ही ViewModel इंस्टेंस मिलेगा. हालांकि, ऐसा तब नहीं होगा, जब हर चिप के लिए, व्यू मॉडल की अलग-अलग कुंजी का इस्तेमाल किया जाए.
  • ViewModels को यूज़र इंटरफ़ेस (यूआई) के लागू करने के तरीके के बारे में जानकारी नहीं होनी चाहिए. ViewModel एपीआई के दिखाए गए तरीकों और यूज़र इंटरफ़ेस (यूआई) की स्टेट फ़ील्ड के नामों को जितना हो सके, सामान्य रखें. इस तरह, आपका ViewModel, किसी भी तरह के यूज़र इंटरफ़ेस (यूआई) के साथ काम कर सकता है: मोबाइल फ़ोन, फ़ोल्डेबल, टैबलेट या Chromebook!
  • ViewModels, ViewModelStoreOwner से ज़्यादा समय तक मौजूद रह सकते हैं. इसलिए, इनमें लाइफ़साइकल से जुड़े एपीआई के कोई रेफ़रंस नहीं होने चाहिए. जैसे, Context या Resources. ऐसा करने से, मेमोरी लीक होने से रोका जा सकता है.
  • ViewModels को अन्य क्लास, फ़ंक्शन या यूज़र इंटरफ़ेस (यूआई) के अन्य कॉम्पोनेंट को पास न करें. इन्हें प्लैटफ़ॉर्म मैनेज करता है. इसलिए, इन्हें प्लैटफ़ॉर्म के जितना हो सके, पास रखें. जैसे, अपनी ऐक्टिविटी, स्क्रीन लेवल का कंपोज़ेबल फ़ंक्शन या नेविगेशन डेस्टिनेशन के पास. इससे, निचले लेवल के कॉम्पोनेंट को ज़रूरत से ज़्यादा डेटा और लॉजिक ऐक्सेस करने से रोका जा सकता है.

ज़्यादा जानकारी

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

Android ऐप्लिकेशन के आर्किटेक्चर की गाइड में, इन फ़ंक्शन को मैनेज करने के लिए, रिपॉज़िटरी क्लास बनाने का सुझाव दिया गया है.

अन्य संसाधन

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

दस्तावेज़

Views का कॉन्टेंट

सैंपल