इस प्रश्न का उत्तर देने के लिए आपको LoaderManager
कोड में खुदाई करने की आवश्यकता है । जबकि LoaderManager के लिए प्रलेखन ही पर्याप्त नहीं है (या यह सवाल नहीं होगा), LoaderManagerImpl के लिए प्रलेखन, अमूर्त LoaderManager के एक उपवर्ग, बहुत अधिक ज्ञानवर्धक है।
initLoader
लोडर के साथ एक विशेष आईडी को इनिशियलाइज़ करने के लिए कॉल करें। यदि इस आईडी में पहले से लोडर जुड़ा हुआ है, तो इसे अपरिवर्तित छोड़ दिया जाता है और किसी भी पिछले कॉलबैक को नए प्रदान किए गए लोगों के साथ बदल दिया जाता है। यदि वर्तमान में आईडी के लिए कोई लोडर नहीं है, तो एक नया बनाया और शुरू किया गया है।
इस फ़ंक्शन का उपयोग आम तौर पर तब किया जाना चाहिए जब कोई घटक इनिशियलाइज़ कर रहा हो, यह सुनिश्चित करने के लिए कि यह जिस लोडर पर निर्भर है, वह बनाया गया है। यह एक मौजूदा लोडर के डेटा को फिर से उपयोग करने की अनुमति देता है यदि पहले से ही एक है, ताकि उदाहरण के लिए जब एक कॉन्फ़िगरेशन बदलने के बाद गतिविधि फिर से बनाई जाए तो उसे अपने लोडर को फिर से बनाने की आवश्यकता न हो।
restartLoader
किसी विशेष आईडी से जुड़े लोडर को फिर से बनाने के लिए कॉल करें। अगर वर्तमान में इस आईडी से जुड़ा कोई लोडर है, तो उसे रद्द / उपयुक्त के रूप में रद्द / नष्ट कर दिया जाएगा। दिए गए तर्कों के साथ एक नया लोडर बनाया जाएगा और इसका डेटा एक बार उपलब्ध होने पर आपको दिया जाएगा।
[...] इस फ़ंक्शन को कॉल करने के बाद, इस आईडी से जुड़े किसी भी पिछले लोडर को अमान्य माना जाएगा, और आपको उनसे कोई और डेटा अपडेट नहीं मिलेगा।
मूल रूप से दो मामले हैं:
- आईडी के साथ लोडर मौजूद नहीं है: दोनों विधियाँ एक नया लोडर बनाएंगी ताकि वहाँ कोई अंतर न हो
- आईडी के साथ लोडर पहले से मौजूद है:
initLoader
केवल एक पैरामीटर के रूप में पारित कॉलबैक को बदल देगा, लेकिन लोडर को रद्द या बंद नहीं करेगा। के लिए एक CursorLoader
है कि साधन कर्सर रहता खुले और सक्रिय (है कि अगर पहले मामला था initLoader
कॉल)। `पुनः आरंभकर्ता, दूसरी ओर, लोडर को रद्द, रोक देगा और नष्ट कर देगा (और कर्सर की तरह अंतर्निहित डेटा स्रोत को बंद कर देगा) और एक नया लोडर बनाएगा (जो एक नया कर्सर भी बनाएगा और लोडर होने पर क्वेरी को फिर से चलाएगा। एक CursorLoader)।
यहाँ दोनों विधियों के लिए सरलीकृत कोड दिया गया है:
initLoader
LoaderInfo info = mLoaders.get(id);
if (info == null) {
// Loader doesn't already exist -> create new one
info = createAndInstallLoader(id, args, LoaderManager.LoaderCallbacks<Object>)callback);
} else {
// Loader exists -> only replace callbacks
info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}
restartLoader
LoaderInfo info = mLoaders.get(id);
if (info != null) {
LoaderInfo inactive = mInactiveLoaders.get(id);
if (inactive != null) {
// does a lot of stuff to deal with already inactive loaders
} else {
// Keep track of the previous instance of this loader so we can destroy
// it when the new one completes.
info.mLoader.abandon();
mInactiveLoaders.put(id, info);
}
}
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
जैसा कि हम देख सकते हैं कि लोडर मौजूद नहीं है (जानकारी == अशक्त) दोनों विधियाँ एक नया लोडर (जानकारी = createAndInstallLoader (...)) बनाएंगी। यदि लोडर पहले से ही मौजूद है तो initLoader
केवल कॉलबैक (info.mCallbacks = ...) को बदल देता है जबकि restartLoader
पुराने लोडर को निष्क्रिय कर देता है (जब नया लोडर अपना काम पूरा कर लेता है) तब यह नष्ट हो जाता है और फिर एक नया बनाता है।
इस प्रकार कहा कि अब यह स्पष्ट है कि कब उपयोग करना है initLoader
और कब उपयोग करना है restartLoader
और यह दो तरीकों के लिए क्यों समझ में आता है।
initLoader
यह सुनिश्चित करने के लिए उपयोग किया जाता है कि एक इनिशियलाइज्ड लोडर है। यदि कोई भी मौजूद नहीं है तो एक नया बनाया जाता है, यदि कोई पहले से मौजूद है तो उसका पुनः उपयोग किया जाता है। हम हमेशा इस तरीके का उपयोग करते हैं UNLESS के लिए हमें एक नए लोडर की आवश्यकता होती है क्योंकि चलाने के लिए क्वेरी बदल गई है (अंतर्निहित डेटा नहीं है, लेकिन CursorLoader के लिए SQL कथन की तरह वास्तविक क्वेरी), जिस स्थिति में हम कॉल करेंगे restartLoader
।
गतिविधि / टुकड़ा जीवन चक्र से एक का उपयोग करने का निर्णय या अन्य विधि के साथ कोई संबंध नहीं है (और एक एक शॉट ध्वज का उपयोग कर कॉल का ट्रैक रखने के रूप में साइमन सुझाव की आवश्यकता नहीं है)! यह निर्णय पूरी तरह से एक नए लोडर के लिए "आवश्यकता" पर आधारित है। यदि हम उसी क्वेरी को चलाना चाहते हैं जिसका हम उपयोग करते हैं initLoader
, यदि हम एक अलग क्वेरी चलाना चाहते हैं जिसका हम उपयोग करते हैं restartLoader
।
हम हमेशा उपयोग कर सकते हैं restartLoader
लेकिन यह अक्षम होगा। एक स्क्रीन रोटेशन के बाद या यदि उपयोगकर्ता ऐप से दूर हो जाता है और बाद में उसी गतिविधि पर लौटता है तो हम आमतौर पर एक ही क्वेरी परिणाम दिखाना चाहते हैं और इसलिए restartLoader
अनावश्यक रूप से लोडर को फिर से बनाएंगे और अंतर्निहित (संभावित रूप से महंगा) क्वेरी परिणाम को खारिज कर देंगे।
लोड किए गए डेटा और उस डेटा को लोड करने के लिए "क्वेरी" के बीच अंतर को समझना बहुत महत्वपूर्ण है। चलो मान लेते हैं कि हम आदेशों के लिए एक तालिका को क्वेरी करते हुए CursorLoader का उपयोग करते हैं। यदि उस तालिका में एक नया आदेश जोड़ा जाता है तो CursorLoader UI को अपडेट करने और नए आदेश ( restartLoader
इस मामले में उपयोग करने की आवश्यकता नहीं) को सूचित करने के लिए onContentChanged () का उपयोग करता है । यदि हम केवल खुले आदेशों को प्रदर्शित करना चाहते हैं, तो हमें एक नई क्वेरी की आवश्यकता है और हम नई क्वेरी restartLoader
को दर्शाते हुए एक नया CursorLoader वापस करने के लिए उपयोग करेंगे ।
क्या दोनों विधियों के बीच कुछ संबंध है?
वे एक नया लोडर बनाने के लिए कोड साझा करते हैं, लेकिन वे अलग-अलग चीजें करते हैं जब एक लोडर पहले से मौजूद है।
कॉलिंग restartLoader
हमेशा कॉल करता है initLoader
?
नहीं, ऐसा कभी नहीं होता।
क्या मैं restartLoader
बिना बुलाए आ सकता हूं initLoader
?
हाँ।
क्या initLoader
डेटा को ताज़ा करने के लिए दो बार कॉल करना सुरक्षित है ?
यह initLoader
दो बार कॉल करने के लिए सुरक्षित है लेकिन कोई डेटा ताज़ा नहीं किया जाएगा।
मुझे दोनों में से एक का उपयोग कब और क्यों करना चाहिए ?
ऊपर मेरे स्पष्टीकरण के बाद यह (उम्मीद) स्पष्ट होना चाहिए।
कॉन्फ़िगरेशन बदलता है
एक LoaderManager कॉन्फ़िगरेशन परिवर्तन (अभिविन्यास परिवर्तन सहित) में अपनी स्थिति को बनाए रखता है, इसलिए आपको लगता है कि हमारे लिए ऐसा करने के लिए कुछ भी नहीं बचा है। फिर से विचार करना...
सबसे पहले, एक LoaderManager कॉलबैक को बनाए नहीं रखता है, इसलिए यदि आप कुछ भी नहीं करते हैं तो आपको अपने कॉलबैक विधियों जैसे onLoadFinished()
और जैसे कॉल प्राप्त नहीं होंगे और यह आपके ऐप को बहुत ही आसानी से तोड़ देगा।
इसलिए हमें initLoader
कॉलबैक विधियों (ए restartLoader
, निश्चित रूप से, बहुत संभव है) को पुनर्स्थापित करने के लिए कम से कम कॉल करना होगा । प्रलेखन कहता है:
यदि कॉल के बिंदु पर कॉल करने वाला चालू स्थिति में है, और अनुरोधित लोडर पहले से मौजूद है और उसने अपना डेटा जेनरेट किया है, तो कॉलबैक onLoadFinished(Loader, D)
को तुरंत (इस फ़ंक्शन के अंदर) कहा जाएगा [...]।
इसका मतलब है कि यदि हम initLoader
अभिविन्यास परिवर्तन के बाद कॉल करते हैं, तो हमें onLoadFinished
तुरंत कॉल मिलेगा क्योंकि डेटा पहले से ही लोड है (यह मानते हुए कि परिवर्तन से पहले मामला था)। जबकि यह सीधे लगता है कि यह मुश्किल हो सकता है (हम सभी एंड्रॉइड को प्यार नहीं करते ...)।
हमें दो मामलों में अंतर करना होगा:
- हैंडल कॉन्फ़िगरेशन स्वयं बदल जाता है: यह Fragments के लिए मामला है जो setRetainInstance (सही) या गतिविधि के
android:configChanges
लिए प्रकट टैग के अनुसार गतिविधि का उपयोग करता है। इन घटकों को एक स्क्रीन घुमाव के बाद ऑनक्रीट कॉल प्राप्त नहीं होगी, इसलिए initLoader/restartLoader
कॉलबैक विधि (जैसे onActivityCreated(Bundle)
) में
कॉल करने के लिए ध्यान रखें
। लोडर (ओं) को शुरू करने में सक्षम होने के लिए, लोडर आईडी को संग्रहीत करने की आवश्यकता होती है (जैसे एक सूची में)। क्योंकि घटक को कॉन्फ़िगरेशन परिवर्तनों के दौरान बनाए रखा जाता है, हम मौजूदा लोडर आईडी और कॉल पर लूप कर सकते हैं initLoader(loaderid,
...)
।
- कॉन्फ़िगरेशन परिवर्तन को स्वयं हैंडल नहीं करता है: इस स्थिति में लोडर ऑनक्रिएट में आरंभीकृत किए जा सकते हैं, लेकिन हमें लोडर आईडी को मैन्युअल रूप से बनाए रखने की आवश्यकता है या हम आवश्यक initLoader / restartLoader कॉल करने में सक्षम नहीं होंगे। अगर आईडी को एक ArrayList में संग्रहीत किया जाता है, तो हम
outState.putIntegerArrayList(loaderIdsKey, loaderIdsArray)
onSaveInstanceState में करेंगे और आईडी को onCreate में पुनर्स्थापित करेंगे:
loaderIdsArray =
savedInstanceState.getIntegerArrayList(loaderIdsKey)
इससे पहले कि हम initLoader call (s) करें।
initLoader
(और सभी कॉलबैक समाप्त हो गए हैं, तो लोडर बेकार है) एक रोटेशन के बाद आपकोonLoadFinished
कॉलबैक नहीं मिलेगा लेकिन यदि आपrestartLoader
अपनी इच्छा का उपयोग करते हैं?