यह कोडलैब Android Kotlin के बुनियादी कोर्स में शामिल है. अगर आप कोडलैब के क्रम में काम करते हैं, तो आपको इस कोर्स का ज़्यादा से ज़्यादा फ़ायदा मिलेगा. सभी कोर्स कोडलैब Android Kotlin से जुड़े बेसिक कोडलैब के लैंडिंग पेज पर दिए गए हैं.
शीर्षक स्क्रीन |
गेम स्क्रीन |
स्कोर स्क्रीन |
परिचय
इस कोडलैब में, आप Android आर्किटेक्चर के किसी एक कॉम्पोनेंट, ViewModel
के बारे में जानेंगे:
- लाइफ़साइकल के हिसाब से डेटा को सेव और मैनेज करने के लिए, आप
ViewModel
क्लास का इस्तेमाल करते हैं.ViewModel
क्लास में, डिवाइस के कॉन्फ़िगरेशन से जुड़े बदलावों, जैसे कि स्क्रीन रोटेशन और कीबोर्ड की उपलब्धता में होने वाले बदलावों का पालन किया जा सकता है. - आप
ViewModel
ऑब्जेक्ट को इंस्टैंशिएट करने और उसे लौटाने के लिए,ViewModelFactory
क्लास का इस्तेमाल करते हैं, जो कॉन्फ़िगरेशन में हुए बदलावों से बचा रहता है.
आपको क्या पता होना चाहिए
- Kotlin में बेसिक Android ऐप्लिकेशन बनाने का तरीका.
- अपने ऐप्लिकेशन में नेविगेशन लागू करने के लिए, नेविगेशन ग्राफ़ को इस्तेमाल करने का तरीका.
- अपने ऐप्लिकेशन के डेस्टिनेशन के बीच नेविगेट करने और नेविगेशन के डेस्टिनेशन के बीच डेटा पास करने के लिए, कोड जोड़ने का तरीका.
- फ़्रैगमेंट और गतिविधि पूरी होने की प्रोसेस कैसे काम करती है.
- Android Studio में लॉगकैट का इस्तेमाल करके, किसी ऐप्लिकेशन में लॉग इन की जानकारी जोड़ने और लॉग पढ़ने का तरीका.
आप इन चीज़ों के बारे में जानेंगे
- सुझाए गए Android ऐप्लिकेशन आर्किटेक्चर को इस्तेमाल करने का तरीका.
- अपने ऐप्लिकेशन में
Lifecycle
,ViewModel
, औरViewModelFactory
क्लास को इस्तेमाल करने का तरीका. - डिवाइस-कॉन्फ़िगरेशन के बदलावों से, यूज़र इंटरफ़ेस (यूआई) डेटा को कैसे बनाए रखें.
- फ़ैक्ट्री का तरीका डिज़ाइन पैटर्न क्या है और इसका इस्तेमाल कैसे किया जाता है.
- इंटरफ़ेस
ViewModelProvider.Factory
का इस्तेमाल करके,ViewModel
ऑब्जेक्ट बनाने का तरीका.
आप क्या कर पाएंगे!
- ऐप्लिकेशन का डेटा सेव करने के लिए
ViewModel
ऐप्लिकेशन में जोड़ें, ताकि डेटा कॉन्फ़िगरेशन में हुए बदलावों के दौरान बचा रहे. - कंस्ट्रक्टर पैरामीटर के साथ
ViewModel
ऑब्जेक्ट को इंस्टैंशिएट करने के लिए,ViewModelFactory
और फ़ैक्ट्री-तरीका डिज़ाइन पैटर्न का इस्तेमाल करें.
लेसन 5 कोडलैब में, आप GuessTheWord ऐप्लिकेशन डेवलप करते हैं. इसकी शुरुआत स्टार्टर कोड से होती है. GuessTheWord दो-खिलाड़ियों वाला चार्टेस-शैली का गेम है, जिसमें खिलाड़ी सबसे ज़्यादा स्कोर हासिल करने के लिए मिलकर काम करते हैं.
पहला खिलाड़ी ऐप्लिकेशन में शब्दों को देखता है और हर एक को एक-एक करके करता है, ताकि यह पक्का हो सके कि वह दूसरे खिलाड़ी को शब्द न दिखाए. दूसरा खिलाड़ी, शब्द का अनुमान लगाने की कोशिश करता है.
गेम खेलने के लिए, पहला खिलाड़ी डिवाइस पर ऐप्लिकेशन खोलता है और एक शब्द देखता है, उदाहरण के लिए, " गिटार,&कोटेशन; जैसा कि नीचे स्क्रीनशॉट में दिखाया गया है.
पहला खिलाड़ी सिर्फ़ शब्द बोलता हुआ सावधान रहता है.
- जब दूसरा खिलाड़ी शब्द का सही अनुमान लगाता है, तो पहला खिलाड़ी ठीक है बटन दबाता है. इससे बटन की संख्या एक बढ़ जाती है और अगला शब्द दिखता है.
- अगर दूसरा खिलाड़ी शब्द का अनुमान नहीं लगा सकता, तो पहला खिलाड़ी छोड़ें बटन को दबाता है. इससे एक शब्द कम हो जाता है और अगले शब्द पर चला जाता है.
- गेम खत्म करने के लिए, गेम खत्म करें बटन दबाएं. (यह सुविधा सीरीज़ के पहले कोडलैब (कोड बनाना सीखना) के स्टार्टर कोड में't है.)
इस टास्क में, आप स्टार्टर ऐप्लिकेशन डाउनलोड करके चलाते हैं और कोड की जांच करते हैं.
पहला चरण: शुरू करना
- GuessTheWord स्टार्टर कोड डाउनलोड करें और प्रोजेक्ट को Android Studio में खोलें.
- ऐप्लिकेशन को Android पर चलने वाले डिवाइस या एम्युलेटर पर चलाएं.
- बटन पर टैप करें. ध्यान दें कि अभी नहीं बटन अगले शब्द को दिखाता है और स्कोर में एक की कमी कर देता है. वहीं, ठीक है बटन अगला शब्द दिखाता है और स्कोर को एक बढ़ा देता है. गेम खत्म करें बटन लागू नहीं किया गया है, इसलिए जब आप इसे टैप करेंगे तो कुछ नहीं होगा.
दूसरा चरण: कोड कदम-दर-कदम निर्देश
- Android Studio में, कोड एक्सप्लोर करें और जानें कि ऐप्लिकेशन कैसे काम करता है.
- नीचे बताई गई फ़ाइलें देखना न भूलें, जो खास तौर पर अहम हैं.
MainActivity.kt
इस फ़ाइल में सिर्फ़ डिफ़ॉल्ट, टेंप्लेट से जनरेट किया गया कोड शामिल है.
res/layout/main_activity.xml
इस फ़ाइल में ऐप्लिकेशन का मुख्य लेआउट शामिल है. जब उपयोगकर्ता ऐप्लिकेशन में नेविगेट करता है, तब NavHostFragment
दूसरे फ़्रैगमेंट को होस्ट करता है.
यूज़र इंटरफ़ेस (यूआई) फ़्रैगमेंट
स्टार्टर कोड में तीन पैकेज होते हैं. यह com.example.android.guesstheword.screens
पैकेज के तीन अलग-अलग पैकेज में होते हैं:
- शीर्षक स्क्रीन के लिए
title/TitleFragment
- गेम स्क्रीन के लिए
game/GameFragment
- स्कोर स्क्रीन के लिए
score/ScoreFragment
screen/title/TitleFragment.kt
शीर्षक फ़्रैगमेंट वह पहली स्क्रीन होती है जो ऐप्लिकेशन लॉन्च होने पर दिखाई जाती है. क्लिक स्क्रीन को चलाएं बटन पर सेट करके, गेम स्क्रीन पर जाएं.
screen/game/GameFragment.kt
यह मुख्य फ़्रैगमेंट है, जिसमें ज़्यादातर गेम की कार्रवाई होती है:
- वैरिएबल, मौजूदा शब्द और मौजूदा स्कोर के लिए तय किए जाते हैं.
wordList
में बताए गएresetList()
तरीके का इस्तेमाल, गेम में इस्तेमाल किए जाने वाले शब्दों की सैंपल सूची है.onSkip()
तरीका स्किप बटन के लिए क्लिक हैंडलर है. यह स्कोर को 1 तक कम कर देता है, फिरnextWord()
तरीके का इस्तेमाल करके अगला शब्द दिखाता है.onCorrect()
तरीका, ठीक है बटन के लिए क्लिक हैंडलर है. इस तरीके कोonSkip()
तरीके की तरह ही लागू किया जाता है. अंतर सिर्फ़ यह है कि यह तरीका घटाने के बजाय स्कोर में 1 जोड़ता है.
screen/score/ScoreFragment.kt
ScoreFragment
, गेम की फ़ाइनल स्क्रीन होती है. यहां, खिलाड़ियों का फ़ाइनल स्कोर दिखता है. इस कोडलैब में, आप इस स्क्रीन को दिखाने और आखिरी स्कोर दिखाने के लिए, इसे लागू करते हैं.
res/navigation/main_navigation.xml
नेविगेशन ग्राफ़ दिखाता है कि फ़्रैगमेंट को नेविगेशन की मदद से कैसे जोड़ा जाता है:
- शीर्षक फ़्रैगमेंट से, उपयोगकर्ता गेम फ़्रैगमेंट पर जा सकता है.
- गेम के फ़्रैगमेंट से, उपयोगकर्ता स्कोर फ़्रैगमेंट पर जा सकते हैं.
- स्कोर फ़्रैगमेंट से, उपयोगकर्ता गेम फ़्रैगमेंट पर वापस नेविगेट कर सकते हैं.
इस टास्क में, आपको GuessTheWord स्टार्टर ऐप्लिकेशन के साथ समस्याएं मिलेंगी.
- स्टार्टर कोड चलाएं और कुछ शब्दों के बाद गेम खेलें. इसके बाद, हर शब्द के बाद अभी नहीं या ठीक है पर टैप करें.
- गेम स्क्रीन पर अब कोई शब्द और मौजूदा स्कोर दिखता है. डिवाइस या एम्युलेटर को घुमाकर, स्क्रीन ओरिएंटेशन में बदलाव करें. ध्यान दें कि मौजूदा स्कोर चला जाता है.
- कुछ और शब्दों में गेम खेलें. जब गेम स्क्रीन कुछ स्कोर के साथ दिखती है, तो ऐप्लिकेशन को बंद करें और दोबारा खोलें. ध्यान दें कि गेम शुरू से शुरू होता है, क्योंकि ऐप्लिकेशन की स्थिति सेव नहीं होती है.
- कुछ शब्दों की मदद से गेम खेलें. इसके बाद, गेम खत्म करें बटन पर टैप करें. ध्यान दें, कुछ नहीं होगा.
ऐप्लिकेशन में समस्याएं:
- स्टार्टर ऐप्लिकेशन, कॉन्फ़िगरेशन के बदलावों के दौरान ऐप्लिकेशन की स्थिति को सेव और बहाल नहीं करता. उदाहरण के लिए, डिवाइस की दिशा बदलने या ऐप्लिकेशन बंद होने और रीस्टार्ट होने पर.
आपonSaveInstanceState()
कॉलबैक का इस्तेमाल करके, इस समस्या को ठीक कर सकते हैं. हालांकि,onSaveInstanceState()
तरीके का इस्तेमाल करने के लिए आपको एक बंडल में अतिरिक्त कोड लिखना होगा. साथ ही, उस स्थिति को वापस पाने के लिए लॉजिक लागू करना होगा. साथ ही, कम डेटा स्टोर किया जा सकता है. - जब उपयोगकर्ता गेम खत्म करें बटन पर टैप करता है, तब गेम स्क्रीन स्कोर स्क्रीन पर नहीं जाती है.
आप इस कोडलैब में ऐप्लिकेशन के आर्किटेक्चर कॉम्पोनेंट के इस्तेमाल से, इन समस्याओं को हल कर सकते हैं.
ऐप्लिकेशन का आर्किटेक्चर
ऐप्लिकेशन आर्किटेक्चर, आपके ऐप्लिकेशन को डिज़ाइन करने का एक तरीका है' क्लास और उनके बीच का संबंध, जैसे कि कोड व्यवस्थित है, खास स्थितियों में अच्छा परफ़ॉर्म करता है, और इसके साथ काम करना आसान है. चार कोडलैब के इस सेट में, GuessTheWord ऐप्लिकेशन में किए गए सुधार, Android ऐप्लिकेशन के आर्किटेक्चर के दिशा-निर्देशों का पालन करते हैं. साथ ही, आप Android आर्किटेक्चर कॉम्पोनेंट का इस्तेमाल करते हैं. Android ऐप्लिकेशन का आर्किटेक्चर, MVVM (मॉडल-व्यू-व्यूमॉडल) आर्किटेक्चर पैटर्न की तरह है.
GuessTheWord ऐप्लिकेशन डिज़ाइन करने के सिद्धांत अलग करने का सिद्धांत अपनाता है और इसे कक्षाओं में बांट दिया जाता है. इसमें हर क्लास के लिए एक अलग समस्या होती है. लेसन के इस पहले कोडलैब में, आप जिन क्लास के साथ काम करते हैं वे हैं यूज़र इंटरफ़ेस (यूआई) कंट्रोलर, ViewModel
, और ViewModelFactory
.
यूज़र इंटरफ़ेस (यूआई) कंट्रोलर
यूज़र इंटरफ़ेस (यूआई) कंट्रोलर, यूज़र इंटरफ़ेस (यूआई) पर आधारित है, जैसे कि Activity
या Fragment
. यूज़र इंटरफ़ेस (यूआई) कंट्रोलर में सिर्फ़ ऐसा लॉजिक होना चाहिए जो यूज़र इंटरफ़ेस (यूआई) और ऑपरेटिंग सिस्टम के इंटरैक्शन को मैनेज करता हो. जैसे, व्यू दिखाना और उपयोगकर्ता का इनपुट कैप्चर करना. यूज़र इंटरफ़ेस (यूआई) कंट्रोलर में, लॉजिक तय करने वाले लॉजिक (जैसे कि लॉजिक) से तय करने वाले लॉजिक न डालें.
GuessTheWord स्टार्टर कोड में, यूज़र इंटरफ़ेस (यूआई) कंट्रोलर तीन फ़्रैगमेंट होते हैं: GameFragment
, ScoreFragment,
, और TitleFragment
. समस्याओं को समझने के लिए डिज़ाइन किए गए मूल सिद्धांतों के कोटेशन और डिज़ाइन के आधार पर, GameFragment
को सिर्फ़ स्क्रीन पर मौजूद गेम के एलिमेंट के बारे में बताने और उपयोगकर्ता के बटन पर टैप करने के साथ-साथ कुछ और जानने की ज़िम्मेदारी है. जब उपयोगकर्ता किसी बटन पर टैप करता है, तो यह जानकारी GameViewModel
को भेज दी जाती है.
ViewModel
ViewModel
में, ViewModel
से जुड़ा फ़्रैगमेंट या गतिविधि दिखाने के लिए डेटा होता है. यूज़र इंटरफ़ेस (यूआई) कंट्रोलर के डेटा को तैयार करने के लिए, ViewModel
आसान तरीके से डेटा का हिसाब और बदलाव कर सकता है. इस आर्किटेक्चर में, ViewModel
फ़ैसला लेता है.GameViewModel
में स्कोर का मान, शब्दों की सूची, और मौजूदा शब्द जैसा डेटा होता है, क्योंकि यह स्क्रीन पर दिखाया जाने वाला डेटा है. GameViewModel
में कारोबार की समझ भी शामिल होती है. इसकी मदद से, यह तय किया जा सकता है कि डेटा की मौजूदा स्थिति क्या है.
ViewModelFactory
ViewModelFactory
कंस्ट्रक्टर पैरामीटर के साथ या उसके बिना, ViewModel
ऑब्जेक्ट को इंस्टैंशिएट करता है.
बाद के कोडलैब में, आप यूज़र इंटरफ़ेस (यूआई) कंट्रोलर और ViewModel
से जुड़े अन्य Android आर्किटेक्चर के कॉम्पोनेंट के बारे में जानते हैं.
ViewModel
क्लास को यूज़र इंटरफ़ेस (यूआई) से जुड़े डेटा को स्टोर और मैनेज करने के लिए डिज़ाइन किया गया है. इस ऐप्लिकेशन में, हर ViewModel
एक फ़्रैगमेंट से जुड़ा होता है.
इस टास्क में, आप अपने पहले ViewModel
को ऐप्लिकेशन में जोड़ते हैं, GameFragment
को GameViewModel
के लिए. आपको यह भी पता चलेगा कि इसका मतलब क्या है और ViewModel
, लाइफ़साइकल की जानकारी देता है.
पहला चरण: GameViewModel क्लास जोड़ना
build.gradle(module:app)
फ़ाइल खोलें.dependencies
ब्लॉक के अंदर,ViewModel
के लिए, Gradle डिपेंडेंसी जोड़ें.
अगर लाइब्रेरी के नए वर्शन का इस्तेमाल किया जा रहा है, तो समाधान वाले ऐप्लिकेशन को उम्मीद के मुताबिक कंपाइल किया जाना चाहिए. अगर इससे समस्या हल नहीं होती है, तो समस्या को हल करने की कोशिश करें या नीचे दिए गए वर्शन पर वापस जाएं.
//ViewModel
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
- पैकेज
screens/game/
फ़ोल्डर में,GameViewModel
नाम की एक नई Kotlin क्लास बनाएं. GameViewModel
क्लास को एब्सट्रैक्ट क्लासViewModel
बढ़ाने की अनुमति दें.- यह समझने में आपकी मदद करने के लिए कि
ViewModel
लाइफ़साइकल की जानकारी कैसे है,log
स्टेटमेंट के साथinit
ब्लॉक जोड़ें.
class GameViewModel : ViewModel() {
init {
Log.i("GameViewModel", "GameViewModel created!")
}
}
दूसरा चरण: onCleared() को ओवरराइड करना और लॉगिंग जोड़ें
जब उससे जुड़ा फ़्रैगमेंट अलग हो जाता है या गतिविधि पूरी हो जाती है, तो ViewModel
खत्म हो जाता है. ViewModel
को नुकसान पहुंचाने से ठीक पहले, संसाधनों को खाली करने के लिए onCleared()
कॉलबैक को कॉल किया जाता है.
GameViewModel
क्लास में,onCleared()
तरीके को बदलें.GameViewModel
की लाइफ़साइकल को ट्रैक करने के लिए,onCleared()
में लॉग स्टेटमेंट जोड़ें.
override fun onCleared() {
super.onCleared()
Log.i("GameViewModel", "GameViewModel destroyed!")
}
तीसरा चरण: GameViewModel को गेम फ़्रैगमेंट से जोड़ना
ViewModel
को किसी यूज़र इंटरफ़ेस (यूआई) कंट्रोलर से जोड़ना ज़रूरी है. दोनों को जोड़ने के लिए, आप यूज़र इंटरफ़ेस (यूआई) कंट्रोलर के अंदर ViewModel
का रेफ़रंस बनाते हैं.
इस चरण में, आप उससे जुड़े यूज़र इंटरफ़ेस (यूआई) कंट्रोलर के GameViewModel
का रेफ़रंस देते हैं, जो GameFragment
है.
GameFragment
क्लास में, क्लास वैरिएबल के तौर पर सबसे ऊपर के लेवल परGameViewModel
टाइप का फ़ील्ड जोड़ें.
private lateinit var viewModel: GameViewModel
चौथा चरण: ViewModel शुरू करना
स्क्रीन को घुमाने जैसे कॉन्फ़िगरेशन के दौरान, फ़्रैगमेंट जैसे यूज़र इंटरफ़ेस (यूआई) कंट्रोलर फिर से बनते हैं. हालांकि, ViewModel
इंस्टेंस अब भी काम कर रहा है. ViewModel
क्लास का इस्तेमाल करके ViewModel
इंस्टेंस बनाने पर, जब भी फ़्रैगमेंट को फिर से बनाया जाता है, तब एक नया ऑब्जेक्ट बन जाता है. इसके बजाय, ViewModelProvider
का इस्तेमाल करके ViewModel
इंस्टेंस बनाएं.
ViewModelProvider
कैसे काम करता है:
ViewModelProvider
मौजूदViewModel
के मौजूद होने पर उसे रिटर्न करता है या अगर पहले से मौजूद नहीं है, तोViewModel
बनाता है.ViewModelProvider
, दिए गए दायरे (गतिविधि या फ़्रैगमेंट) के साथViewModel
इंस्टेंस बनाता है.- जब तक स्कोप उपलब्ध है, तब तक
ViewModel
बनाया गया है. उदाहरण के लिए, अगर दायरा फ़्रैगमेंट है, तोViewModel
को तब तक रखा जाता है, जब तक फ़्रैगमेंट अलग नहीं हो जाता.
ViewModelProvider
बनाने के लिए, ViewModelProviders.of()
वाले तरीके का इस्तेमाल करके, ViewModel
को शुरू करें:
GameFragment
क्लास में,viewModel
वैरिएबल शुरू करें. बाइंडिंग वैरिएबल की परिभाषा के बाद, इस कोड कोonCreateView()
में डालें.ViewModelProviders.of()
वाले तरीके का इस्तेमाल करें औरGameFragment
कॉन्टेक्स्ट औरGameViewModel
क्लास में पास करें.ViewModel
ऑब्जेक्ट के शुरू होने से ऊपर,ViewModelProviders.of()
तरीके का कॉल लॉग करने के लिए एक लॉग स्टेटमेंट जोड़ें.
Log.i("GameFragment", "Called ViewModelProviders.of")
viewModel = ViewModelProviders.of(this).get(GameViewModel::class.java)
- ऐप्लिकेशन चलाएं. Android Studio में, लॉगकैट पैनल खोलें और
Game
पर फ़िल्टर करें. अपने डिवाइस या एम्युलेटर पर चलाएं बटन पर टैप करें. गेम स्क्रीन खुलती है.
जैसा कि लॉगकैट में दिखाया गया है,GameViewModel
बनाने के लिएGameFragment
काonCreateView()
तरीका,ViewModelProviders.of()
तरीके को कॉल करता है.GameFragment
औरGameViewModel
में जोड़े गए लॉगिंग स्टेटमेंट, लॉगकैट में दिखते हैं.
- अपने डिवाइस या एम्युलेटर पर ऑटो-रोटेट की सेटिंग चालू करें. साथ ही, स्क्रीन की दिशा को कई बार बदलें.
GameFragment
को हर बार बंद किया जाता है और फिर से बनाया जाता है, इसलिए हर बारViewModelProviders.of()
को कॉल किया जाता है. हालांकि,GameViewModel
को सिर्फ़ एक बार बनाया जाता है. साथ ही, इसे हर कॉल के लिए न तो बनाया जाता है और न ही खत्म किया जाता है.
I/GameFragment: Called ViewModelProviders.of I/GameViewModel: GameViewModel created! I/GameFragment: Called ViewModelProviders.of I/GameFragment: Called ViewModelProviders.of I/GameFragment: Called ViewModelProviders.of
- गेम से बाहर निकलें या गेम के फ़्रैगमेंट से बाहर नेविगेट करें.
GameFragment
खत्म कर दिया गया है. इससे जुड़ेGameViewModel
को भी बंद कर दिया जाता है और कॉलबैकonCleared()
को कॉल किया जाता है.
I/GameFragment: Called ViewModelProviders.of I/GameViewModel: GameViewModel created! I/GameFragment: Called ViewModelProviders.of I/GameFragment: Called ViewModelProviders.of I/GameFragment: Called ViewModelProviders.of I/GameViewModel: GameViewModel destroyed!
ViewModel
, कॉन्फ़िगरेशन में होने वाले बदलावों में बचा रहता है. इसलिए, यह उस डेटा के लिए अच्छी जगह है जिसके लिए कॉन्फ़िगरेशन में हुए बदलावों को लागू करना ज़रूरी है:
ViewModel
में स्क्रीन पर डेटा दिखाएं और उसे प्रोसेस करने के लिए कोड डालें.ViewModel
में फ़्रैगमेंट, गतिविधियां या व्यू के रेफ़रंस कभी नहीं होने चाहिए, क्योंकि गतिविधियां, फ़्रैगमेंट, और व्यू कॉन्फ़िगरेशन में होने वाले बदलावों से बचे नहीं होते.
तुलना के लिए, ViewModel
को जोड़ने से पहले और ViewModel
जोड़ने के बाद, यहां दिया गया है कि GameFragment
यूज़र इंटरफ़ेस (यूआई) डेटा का इस्तेमाल स्टार्टर ऐप्लिकेशन में कैसे किया जाता है:
ViewModel
जोड़ने से पहले:
जब ऐप्लिकेशन को स्क्रीन बदलने जैसे कॉन्फ़िगरेशन में बदलाव किया जाता है, तो गेम फ़्रैगमेंट खत्म हो जाता है और उसे फिर से बना दिया जाता है. डेटा खो जाता है.ViewModel
को जोड़ने और गेम के फ़्रैगमेंट के #39; यूज़र इंटरफ़ेस (यूआई) के डेटा कोViewModel
में ले जाने के बाद:
फ़्रैगमेंट को जो भी डेटा दिखाना होता है वह अबViewModel
है. ऐप्लिकेशन के कॉन्फ़िगरेशन में बदलाव होने पर,ViewModel
ऐप्लिकेशन सेव रहता है और डेटा को सेव रखा जाता है.
इस टास्क में, आप डेटा को प्रोसेस करने के तरीकों के साथ-साथ ऐप्लिकेशन और # यूज़र इंटरफ़ेस (यूआई) डेटा को GameViewModel
क्लास में ले जाते हैं. ऐसा आप इसलिए करते हैं, ताकि कॉन्फ़िगरेशन के बदलावों के दौरान डेटा बना रहे.
कदम 1: डेटा फ़ील्ड और डेटा प्रोसेसिंग को ViewModel में ले जाना
इन डेटा फ़ील्ड और तरीकों को GameFragment
से GameViewModel
में ले जाएं:
word
,score
, औरwordList
डेटा फ़ील्ड को एक जगह से दूसरी जगह ले जाएं. पक्का करें किword
औरscore
private
न हों.
बाइंडिंग वैरिएबल,GameFragmentBinding
की जगह न बदलें, क्योंकि इसमें व्यू का रेफ़रंस शामिल है. इस वैरिएबल का इस्तेमाल लेआउट को इनफ़्लेट करने, क्लिक लिसनर को सेट अप करने, और स्क्रीन पर डेटा दिखाने के लिए किया जाता है—फ़्रैगमेंट की ज़िम्मेदारियां.resetList()
औरnextWord()
मैथड को एक से दूसरी जगह ले जाएं. इन तरीकों से तय होता है कि स्क्रीन पर कौनसा शब्द दिखाया जाएगा.onCreateView()
तरीके के अंदर, मेथड कॉल कोresetList()
औरnextWord()
मेंGameViewModel
केinit
ब्लॉक में ले जाएं.
ये तरीकेinit
ब्लॉक में होने चाहिए, क्योंकि जबViewModel
बनाया जाता है, तब आपको शब्द सूची रीसेट करनी चाहिए, न कि हर बार फ़्रैगमेंट बनाने पर. आपGameFragment
केinit
ब्लॉक में लॉग स्टेटमेंट मिटा सकते हैं.
GameFragment
में onSkip()
और onCorrect()
क्लिक हैंडलर में डेटा प्रोसेस करने और यूज़र इंटरफ़ेस (यूआई) को अपडेट करने के लिए कोड होता है. यूज़र इंटरफ़ेस (यूआई) को अपडेट करने का कोड फ़्रैगमेंट में होना चाहिए, लेकिन डेटा प्रोसेस करने का कोड ViewModel
पर ले जाना ज़रूरी है.
अभी के लिए, दोनों जगहों पर एक जैसे तरीके डालें:
onSkip()
औरonCorrect()
तरीकों कोGameFragment
सेGameViewModel
में कॉपी करें.GameViewModel
में, पक्का करें किonSkip()
औरonCorrect()
मेथडprivate
न हों, क्योंकि आप फ़्रैगमेंट से इन तरीकों का रेफ़रंस देंगे.
यह GameViewModel
फ़ैक्टर के लिए कोड है, जिसे रीफ़ैक्टर करके:
class GameViewModel : ViewModel() {
// The current word
var word = ""
// The current score
var score = 0
// The list of words - the front of the list is the next word to guess
private lateinit var wordList: MutableList<String>
/**
* Resets the list of words and randomizes the order
*/
private fun resetList() {
wordList = mutableListOf(
"queen",
"hospital",
"basketball",
"cat",
"change",
"snail",
"soup",
"calendar",
"sad",
"desk",
"guitar",
"home",
"railway",
"zebra",
"jelly",
"car",
"crow",
"trade",
"bag",
"roll",
"bubble"
)
wordList.shuffle()
}
init {
resetList()
nextWord()
Log.i("GameViewModel", "GameViewModel created!")
}
/**
* Moves to the next word in the list
*/
private fun nextWord() {
if (!wordList.isEmpty()) {
//Select and remove a word from the list
word = wordList.removeAt(0)
}
updateWordText()
updateScoreText()
}
/** Methods for buttons presses **/
fun onSkip() {
if (!wordList.isEmpty()) {
score--
}
nextWord()
}
fun onCorrect() {
if (!wordList.isEmpty()) {
score++
}
nextWord()
}
override fun onCleared() {
super.onCleared()
Log.i("GameViewModel", "GameViewModel destroyed!")
}
}
यह GameFragment
को ध्यान में रखते हुए कोड दिया गया है.
/**
* Fragment where the game is played
*/
class GameFragment : Fragment() {
private lateinit var binding: GameFragmentBinding
private lateinit var viewModel: GameViewModel
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate view and obtain an instance of the binding class
binding = DataBindingUtil.inflate(
inflater,
R.layout.game_fragment,
container,
false
)
Log.i("GameFragment", "Called ViewModelProviders.of")
viewModel = ViewModelProviders.of(this).get(GameViewModel::class.java)
binding.correctButton.setOnClickListener { onCorrect() }
binding.skipButton.setOnClickListener { onSkip() }
updateScoreText()
updateWordText()
return binding.root
}
/** Methods for button click handlers **/
private fun onSkip() {
if (!wordList.isEmpty()) {
score--
}
nextWord()
}
private fun onCorrect() {
if (!wordList.isEmpty()) {
score++
}
nextWord()
}
/** Methods for updating the UI **/
private fun updateWordText() {
binding.wordText.text = word
}
private fun updateScoreText() {
binding.scoreText.text = score.toString()
}
}
दूसरा चरण: GameFragment में क्लिक हैंडलर और डेटा फ़ील्ड के रेफ़रंस अपडेट करना
GameFragment
में,onSkip()
औरonCorrect()
तरीके अपडेट करें. स्कोर को अपडेट करने के लिए कोड को हटाएं और इसके बजायviewModel
पर उससे जुड़ेonSkip()
औरonCorrect()
तरीकों को कॉल करें.- आपने
nextWord()
का तरीकाViewModel
में बदला है, इसलिए गेम फ़्रैगमेंट इसे ऐक्सेस नहीं कर सकता.GameFragment
केonSkip()
औरonCorrect()
वाले तरीके में, कॉल कोupdateScoreText()
औरupdateWordText()
से बदलें. इन तरीकों से स्क्रीन पर डेटा दिखता है.
private fun onSkip() {
viewModel.onSkip()
updateWordText()
updateScoreText()
}
private fun onCorrect() {
viewModel.onCorrect()
updateScoreText()
updateWordText()
}
GameFragment
में,GameViewModel
वैरिएबल का इस्तेमाल करने के लिएscore
औरword
वैरिएबल अपडेट करें, क्योंकि ये वैरिएबल अबGameViewModel
में हैं.
private fun updateWordText() {
binding.wordText.text = viewModel.word
}
private fun updateScoreText() {
binding.scoreText.text = viewModel.score.toString()
}
GameViewModel
में,nextWord()
तरीके के अंदर से,updateWordText()
औरupdateScoreText()
तरीकों में से कॉल हटाएं. अब इन तरीकों सेGameFragment
से कॉल किया जा रहा है.- ऐप्लिकेशन बनाएं और पक्का करें कि उसमें कोई गड़बड़ी न हो. अगर आपको कोई गड़बड़ी मिलती है, तो प्रोजेक्ट को साफ़ करके फिर से बनाएं.
- ऐप्लिकेशन चलाएं और कुछ शब्दों के साथ गेम खेलें. गेम स्क्रीन पर रहते हुए, डिवाइस को घुमाएं. ध्यान दें कि ओरिएंटेशन बदलने के बाद मौजूदा स्कोर और मौजूदा शब्द को बनाए रखा जाता है.
आपने कमाल कर दिया! अब आपके ऐप्लिकेशन का पूरा डेटा ViewModel
में सेव कर दिया गया है. इसलिए, इसे कॉन्फ़िगरेशन में किए गए बदलावों के दौरान सेव किया जाता है.
इस टास्क में, आप गेम खत्म करें बटन के लिए क्लिक लिसनर लागू करते हैं.
GameFragment
नाम मेंonEndGame()
नाम का एक तरीका जोड़ें. जब उपयोगकर्ता गेम खत्म करें बटन पर टैप करेगा, तबonEndGame()
तरीके को कॉल किया जाएगा.
private fun onEndGame() {
}
GameFragment
में,onCreateView()
वाले तरीके में वह कोड ढूंढें जो ठीक है और छोड़ें बटन के लिए, क्लिक लिसनर सेट करता है. इन दो लाइनों के ठीक नीचे, गेम खत्म करें बटन के लिए एक क्लिक लिसनर सेट करें. बाइंडिंग वैरिएबल,binding
का इस्तेमाल करें. क्लिक लिसनर के अंदर,onEndGame()
तरीके को कॉल करें.
binding.endGameButton.setOnClickListener { onEndGame() }
GameFragment
में, ऐप्लिकेशन को स्कोर स्क्रीन पर नेविगेट करने के लिएgameFinished()
नाम का तरीका जोड़ें. Safe Args का इस्तेमाल करके, स्कोर को तर्क के तौर पर पास करें.
/**
* Called when the game is finished
*/
private fun gameFinished() {
Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
val action = GameFragmentDirections.actionGameToScore()
action.score = viewModel.score
NavHostFragment.findNavController(this).navigate(action)
}
onEndGame()
तरीके में,gameFinished()
तरीके पर कॉल करें.
private fun onEndGame() {
gameFinished()
}
- ऐप्लिकेशन चलाएं, गेम खेलें, और कुछ शब्दों के बीच साइकल चलाएं. गेम खत्म करें बटन पर टैप करें. ध्यान दें कि ऐप्लिकेशन, स्कोर स्क्रीन पर जाता है. हालांकि, फ़ाइनल स्कोर नहीं दिखता. आप इसे अगले टास्क में ठीक कर देते हैं.
जब उपयोगकर्ता गेम खत्म करता है, तो ScoreFragment
स्कोर नहीं दिखाता. आप चाहते हैं कि ScoreFragment
तक स्कोर दिखाने के लिए ViewModel
होल्ड किया जाए. आप ViewModel
फ़ैक्ट्री मेथड पैटर्न का इस्तेमाल करके, स्कोर वैल्यू में पास हो सकते हैं.
फ़ैक्ट्री मेथड एक क्रिएटिव डिज़ाइन पैटर्न है, जिसमें ऑब्जेक्ट बनाने के लिए फ़ैक्ट्री के तरीकों का इस्तेमाल किया जाता है. फ़ैक्ट्री तरीका एक ऐसा तरीका है जिससे एक ही क्लास का इंस्टेंस मिलता है.
इस टास्क में, आप स्कोर फ़्रैगमेंट के लिए पैरामीटर वाले कंस्ट्रक्टर और ViewModel
को इंस्टैंशिएट करने के लिए, फ़ैक्ट्री तरीके का इस्तेमाल करके ViewModel
बनाते हैं.
score
पैकेज में,ScoreViewModel
नाम की एक नई Kotlin क्लास बनाएं. स्कोर फ़्रैगमेंट के लिए यह क्लासViewModel
होगी.ScoreViewModel
क्लास कोViewModel.
से बढ़ाकर, फ़ाइनल स्कोर के लिए कंस्ट्रक्टर पैरामीटर जोड़ें.init
ब्लॉक को लॉग स्टेटमेंट के साथ जोड़ें.ScoreViewModel
क्लास में, फ़ाइनल स्कोर सेव करने के लिए,score
नाम का एक वैरिएबल जोड़ें.
class ScoreViewModel(finalScore: Int) : ViewModel() {
// The final score
var score = finalScore
init {
Log.i("ScoreViewModel", "Final score is $finalScore")
}
}
score
पैकेज में जाकर,ScoreViewModelFactory
नाम की एक और Kotlin क्लास बनाएं. इस क्लास की ज़िम्मेदारीScoreViewModel
ऑब्जेक्ट को इंस्टैंशिएट करने की होगी.ScoreViewModelFactory
क्लास कोViewModelProvider.Factory
से बढ़ाएं. फ़ाइनल स्कोर के लिए कंस्ट्रक्टर पैरामीटर जोड़ें.
class ScoreViewModelFactory(private val finalScore: Int) : ViewModelProvider.Factory {
}
ScoreViewModelFactory
में, Android Studio ऐसे एलिमेंट के बारे में गड़बड़ी दिखाता है जिसे लागू नहीं किया गया है. गड़बड़ी को ठीक करने के लिए,create()
के तरीके को बदलें.create()
तरीके में, नया बनाया गयाScoreViewModel
ऑब्जेक्ट दिखाएं.
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(ScoreViewModel::class.java)) {
return ScoreViewModel(finalScore) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
ScoreFragment
में,ScoreViewModel
औरScoreViewModelFactory
के लिए क्लास वैरिएबल बनाएं.
private lateinit var viewModel: ScoreViewModel
private lateinit var viewModelFactory: ScoreViewModelFactory
ScoreFragment
में,onCreateView()
वैरिएबल के अंदर,binding
वैरिएबल की शुरुआत करने के बाद,viewModelFactory
को शुरू करें.ScoreViewModelFactory
का इस्तेमाल करें. आर्ग्युमेंट बंडल से फ़ाइनल स्कोर में कंस्ट्रक्टर पैरामीटर के तौर परScoreViewModelFactory()
को पास करें.
viewModelFactory = ScoreViewModelFactory(ScoreFragmentArgs.fromBundle(arguments!!).score)
onCreateView(
में,viewModelFactory
शुरू करने के बाद,viewModel
ऑब्जेक्ट शुरू करें.ViewModelProviders.of()
तरीके को कॉल करें और उससे जुड़े स्कोर फ़्रैगमेंट का संदर्भ पास करें औरviewModelFactory
. इससेviewModelFactory
क्लास.
में बताए गए तरीके सेScoreViewModel
ऑब्जेक्ट बन जाएगा
viewModel = ViewModelProviders.of(this, viewModelFactory)
.get(ScoreViewModel::class.java)
onCreateView()
तरीके में,viewModel
शुरू करने के बाद,scoreText
व्यू के टेक्स्ट कोScoreViewModel
में बताए गए फ़ाइनल स्कोर पर सेट करें.
binding.scoreText.text = viewModel.score.toString()
- अपना ऐप्लिकेशन चलाएं और गेम खेलें. कुछ या सभी शब्दों पर जाने के बाद, गेम खत्म करें पर टैप करें. ध्यान दें कि स्कोर फ़्रैगमेंट अब फ़ाइनल स्कोर दिखाता है.
- ज़रूरी नहीं:
ScoreViewModel
पर फ़िल्टर करके, लॉगकैट मेंScoreViewModel
लॉग देखें. स्कोर की वैल्यू दिखनी चाहिए.
2019-02-07 10:50:18.328 com.example.android.guesstheword I/ScoreViewModel: Final score is 15
इस टास्क में, ViewModel
का इस्तेमाल करने के लिए आपने ScoreFragment
लागू किया. आपने ViewModelFactory
इंटरफ़ेस का इस्तेमाल करके, ViewModel
के लिए पैरामीटर वाला कंस्ट्रक्टर बनाने का तरीका भी सीखा.
बधाई हो! आपने ViewModel
आर्किटेक्चर वाले किसी कॉम्पोनेंट का इस्तेमाल करने के लिए, अपने ऐप्लिकेशन का आर्किटेक्चर बदल दिया है. आपने ऐप्लिकेशन की लाइफ़साइकल से जुड़ी समस्या हल कर ली है. अब गेम का डेटा, कॉन्फ़िगरेशन में हुए बदलावों से बचा रहता है. आपने ViewModelFactory
इंटरफ़ेस का इस्तेमाल करके, पैरामीटर तैयार करने वाले कंस्ट्रक्टर बनाने का तरीका भी सीखा.
Android Studio प्रोजेक्ट: GuessTheWord
- Android ऐप्लिकेशन आर्किटेक्चर के दिशा-निर्देशों से, अलग-अलग ज़िम्मेदारियों वाली कक्षाओं को अलग करने का सुझाव मिलता है.
- यूज़र इंटरफ़ेस (यूआई) कंट्रोलर, यूज़र इंटरफ़ेस (यूआई) पर आधारित क्लास होता है, जैसे कि
Activity
याFragment
. यूज़र इंटरफ़ेस (यूआई) कंट्रोलर में सिर्फ़ वह लॉजिक होना चाहिए जो यूज़र इंटरफ़ेस (यूआई) और ऑपरेटिंग सिस्टम के इंटरैक्शन को मैनेज करता हो; यूज़र इंटरफ़ेस (यूआई) में दिखाने के लिए डेटा शामिल नहीं होना चाहिए. उस डेटा कोViewModel
में डालें. ViewModel
क्लास, यूज़र इंटरफ़ेस (यूआई) से जुड़ा डेटा सेव और मैनेज करता है.ViewModel
क्लास, डेटा रोटेशन जैसे कॉन्फ़िगरेशन बदलावों से बच सकती है.ViewModel
, सुझाए गए Android आर्किटेक्चर कॉम्पोनेंट में से एक है.ViewModelProvider.Factory
एक इंटरफ़ेस है, जिसका इस्तेमाल करके आपViewModel
ऑब्जेक्ट बना सकते हैं.
नीचे दी गई टेबल, यूज़र इंटरफ़ेस (यूआई) कंट्रोलर की तुलना ViewModel
इंस्टेंस से करती है जिनमें उनका डेटा होता है:
यूज़र इंटरफ़ेस (यूआई) कंट्रोलर | ViewModel |
यूज़र इंटरफ़ेस (यूआई) कंट्रोलर का उदाहरण | इस कोडलैब में बनाया गया |
इसमें यूज़र इंटरफ़ेस (यूआई) में दिखाया जाने वाला डेटा शामिल नहीं है. | इसमें ऐसा डेटा शामिल है जिसे यूज़र इंटरफ़ेस (यूआई) कंट्रोलर, यूज़र इंटरफ़ेस (यूआई) में दिखाता है. |
इसमें डेटा दिखाने के लिए कोड और क्लिक लिसनर जैसे उपयोगकर्ता इवेंट कोड शामिल होते हैं. | डेटा प्रोसेसिंग के लिए कोड शामिल है. |
हर कॉन्फ़िगरेशन बदलाव के दौरान खत्म की गई और फिर से बनाई गई. | सिर्फ़ तब खत्म होता है, जब गतिविधि से जुड़ा यूज़र इंटरफ़ेस (यूआई) कंट्रोलर हमेशा के लिए बंद हो जाता है—किसी गतिविधि के लिए, गतिविधि खत्म होने पर या फ़्रैगमेंट के होने पर, जब फ़्रैगमेंट को अलग किया जाता है. |
इसमें व्यू शामिल हैं. | इसमें गतिविधियों, फ़्रैगमेंट या व्यू का रेफ़रंस कभी नहीं होना चाहिए, क्योंकि ये कॉन्फ़िगरेशन में हुए बदलावों में बदलाव नहीं करते. हालांकि, |
इसमें, | इसमें संबंधित यूज़र इंटरफ़ेस (यूआई) कंट्रोलर का कोई रेफ़रंस शामिल नहीं है. |
Udcity कोर्स:
Android डेवलपर दस्तावेज़:
- ViewModel की खास जानकारी
- लाइफ़साइकल के कॉम्पोनेंट के साथ लाइफ़साइकल मैनेज करना
- ऐप्लिकेशन के आर्किटेक्चर की गाइड
ViewModelProvider
ViewModelProvider.Factory
अन्य:
- MVVM (मॉडल-व्यू-व्यूमॉडल) आर्किटेक्चर पैटर्न.
- समस्याओं को अलग करना (SoC) डिज़ाइन का सिद्धांत
- फ़ैक्ट्री तरीका पैटर्न
इस सेक्शन में उन छात्र-छात्राओं के लिए गृहकार्य की असाइनमेंट की सूची दी गई है जो इस कोडलैब के ज़रिए एक शिक्षक की देखरेख में कोर्स में काम कर रहे हैं. यह क्रिएटर का काम #33 पर निर्भर करता है:
- अगर ज़रूरी हो, तो होमवर्क असाइन करें.
- छात्र-छात्राओं को होमवर्क के असाइनमेंट सबमिट करने के तरीके के बारे में बताएं.
- होमवर्क असाइनमेंट को ग्रेड दें.
शिक्षक इन सुझावों का इस्तेमाल जितनी चाहें उतनी कम या ज़्यादा कर सकते हैं. साथ ही, उन्हें अपने हिसाब से कोई भी होमवर्क असाइन करना चाहिए.
अगर आप इस कोडलैब के ज़रिए खुद काम कर रहे हैं, तो बेझिझक इन होमवर्क असाइनमेंट का इस्तेमाल करें.
इन सवालों के जवाब दें
पहला सवाल
डिवाइस-कॉन्फ़िगरेशन में बदलाव के दौरान डेटा खोने से बचने के लिए, क्या आपको ऐप्लिकेशन डेटा को किस कक्षा में सेव करना चाहिए?
ViewModel
LiveData
Fragment
Activity
दूसरा सवाल
ViewModel
में फ़्रैगमेंट, गतिविधियों या व्यू के रेफ़रंस कभी नहीं होने चाहिए. सही या गलत?
- सही
- गलत
तीसरा सवाल
ViewModel
कब खत्म होता है?
- जब डिवाइस का ओरिएंटेशन बदलने के दौरान, इससे जुड़े यूज़र इंटरफ़ेस (यूआई) कंट्रोलर को खत्म किया जाता और फिर से बनाया जाता है.
- ओरिएंटेशन में बदलाव.
- जब असोसिएट किया गया यूज़र इंटरफ़ेस (यूआई) कंट्रोलर पूरा हो जाता है (अगर यह कोई गतिविधि है) या अलग किया गया है (अगर यह एक # फ़्रैगमेंट है).
- जब उपयोगकर्ता 'वापस जाएं' बटन दबाता है.
चौथा सवाल
ViewModelFactory
इंटरफ़ेस किस लिए है?
ViewModel
ऑब्जेक्ट इंस्टैंशिएट करें.- ओरिएंटेशन में बदलाव के दौरान डेटा बनाए रखना.
- स्क्रीन पर दिखाया जा रहा डेटा रीफ़्रेश किया जा रहा है.
- ऐप्लिकेशन डेटा बदलने पर सूचनाएं पाना.
अगला लेसन शुरू करें:
इस कोर्स में दिए गए दूसरे कोडलैब के लिंक के लिए, Android Kotlin की बुनियादी बातें कोडलैब का लैंडिंग पेज देखें.