
प्रत्येक एंड्रॉइड डेवलपर ने सूचियों को प्रदर्शित करने के लिए RecyclerView
का उपयोग किया और प्रत्येक ने 2016 में DiffUtil
मैजिक क्लास दिखाई देने तक सूची में डेटा को अपडेट करने की समस्या का सामना किया। मैं उंगलियों पर समझाता हूँ कि यह वास्तव में कैसे काम करता है, और उसके जादू को दूर करने की कोशिश करता है।
थोड़ा सा इतिहास
मोबाइल एप्लिकेशन में सबसे आम तत्वों में से एक सूची है, हमारे मामले में RecyclerView
। ये किसी भी चीज़ की सूची हो सकती है: कार्यालय के पते, सामाजिक नेटवर्क में दोस्तों की सूची। नेटवर्क, टैक्सी अनुप्रयोगों में आदेश इतिहास, आदि। इन सभी मामलों को सूची में डेटा को लगातार नए में बदलने की आवश्यकता से एकजुट किया जाता है, जब, उदाहरण के लिए, उपयोगकर्ता ने ताज़ा करने के लिए स्वाइप किया, सूची को फ़िल्टर किया या किसी अन्य तरीके से पीछे से नए डेटा का एक पैकेट प्राप्त किया।
इस व्यवहार को कार्यान्वित करने के लिए, आधुनिक एंड्रॉइड डेवलपर के पूर्वज ने मैन्युअल रूप से डेटा का चयन किया और कैसे बदला, और RecyclerView
से उपयुक्त तरीकों को बुलाया। हालाँकि, सब कुछ बदल गया जब Google ने डिफ्यूटल को जोड़ने के लिए समर्थन लाइब्रेरी संस्करण 25.1.0 जारी किया, जिसने आपको पूरी तरह से DiffUtil
पुनर्निर्माण के बिना पुरानी सूची को नए रूप में बदलने की अनुमति दी। इस लेख में, मैं DiffUtil
के जादू को दूर DiffUtil
और DiffUtil
कि यह कैसे काम करता है।
डिफ्यूटिल के साथ कैसे काम करें?
DiffUtil
साथ काम करने के लिए DiffUtil
आपको DiffUtil
को लागू करना होगा, calculateDiff(@NonNull Callback cb)
विधि को कॉल करें calculateDiff(@NonNull Callback cb)
और प्राप्त DiffResult
को लागू करें DiffResult
को DiffResult
dispatchUpdatesTo()
विधि का उपयोग करके। क्या होता है जब calucalteDiff(@NonNull Callback cd)
विधि कहा जाता है? यह विधि एक DiffResult
देता है, जिसमें मूल सूची को एक नए में परिवर्तित करने के लिए संचालन का एक सेट होता है। अद्यतन notifyItemRangeInserted
, notifyItemRangeRemoved
, notifyItemMoved
और notifyItemRangeChanged
लिए कॉल द्वारा लागू किए जाते हैं। पहले तीन तरीके सूची की संरचना को बदलते हैं, अर्थात् तत्वों की स्थिति, तत्वों को स्वयं बदले बिना और उन पर onBindViewHolder()
पर (तत्व जोड़े जाने के अपवाद के साथ)। उत्तरार्द्ध तत्व को स्वयं बदलता है और तत्व के दृश्य को बदलने के लिए onBindViewHolder()
कहता है।
DiffUtil
मायर्स एल्गोरिथ्म का उपयोग करते हुए मतभेदों के लिए दो सूचियों की जांच करता है, जो केवल परिवर्तनों की उपस्थिति / अनुपस्थिति को निर्धारित करता है, लेकिन यह नहीं जानता कि तत्वों की आवाजाही कैसे पता करें। ऐसा करने के लिए, DiffUtil
मायर्स एल्गोरिथ्म (इस पर बाद में) द्वारा बनाए गए DiffUtil
के माध्यम से चलता है, और फिर आंदोलनों की खोज करता है। DiffResult
का गठन किया गया है
यदि एल्गोरिथ्म तत्वों की गति की जांच नहीं करता है और
, जहां P जोड़ा और हटाए गए तत्वों की संख्या है।
मायर्स एल्गोरिथ्म
अगला, उंगलियों पर मायर्स एल्गोरिथ्म की एक व्याख्या पर विचार किया जाएगा, एल्गोरिथ्म के गणितीय स्पष्टीकरण के लिंक (साथ ही विषय पर अन्य शांत लेख) लेख के अंत में होंगे। दो अनुक्रमों पर विचार करें: BACAAC और CBCBAB। पहले अनुक्रम पर परिवर्तनों का एक क्रम लिखना आवश्यक है, जिसके बाद हमें दूसरा मिलता है। हम निम्नानुसार तालिका में अनुक्रम लिखते हैं: पुरानी सूची कॉलम के पहले तत्वों को दर्शाती है, और नई सूची पंक्तियों के पहले तत्व होंगे।

कोशिकाओं को पार करें जिसमें दोनों अनुक्रमों के समान तत्व प्रतिच्छेद करते हैं:

एक और कार्य मैट्रिक्स के ऊपरी बाएं कोने से निचले दाएं कोने तक कम से कम चरणों में प्राप्त करना है। आप क्षैतिज और ऊर्ध्वाधर चेहरों के साथ आगे बढ़ सकते हैं। यदि आप उस बिंदु से टकराते हैं जहां विकर्ण रेखा शुरू होती है, तो आपको इसके साथ चलना चाहिए, लेकिन इस तरह के एक कदम की लागत 0. तदनुसार, किनारों के साथ एक कदम की लागत 1 है।

बिंदु (0; 0) से हम दाईं ओर और नीचे जा सकते हैं। नीचे जाते समय, आपको अतिरिक्त रूप से तिरछे जाना चाहिए। एक चरण में किए गए आंदोलन को एक सांप कहा जाता है, इस मामले में 2 सांप प्राप्त हुए: (0; 0) -> (0; 1) और (0; 0) -> (1; 2)। तीर सांप के अंत को इंगित करता है, अर्थात। यदि ऊर्ध्वाधर / क्षैतिज कदम के बाद विकर्ण के साथ एक अनिवार्य कदम है, तो तीर विकर्ण के साथ कदम पर होगा। शुरुआती बिंदु से लेकर अंतिम तक सांपों का पूरा निर्माण नीचे दिखाया गया है। वीडियो पर कुछ रास्तों को छोड़ दिया गया क्योंकि जाहिर है सबसे कम नहीं थे।

नतीजतन, हमें कई संभव छोटे रास्ते मिलते हैं, उनमें से कुछ नीचे प्रदर्शित किए गए हैं।


किसी अनुक्रम को दूसरे में परिवर्तित करने के लिए क्रियाओं (स्क्रिप्ट) के अनुक्रम को निर्धारित करने के लिए दूर से बाईं ओर एक मैट्रिक्स कैसे गुजर सकता है? क्षैतिज, ऊर्ध्वाधर और विकर्ण चरणों का क्या मतलब है? संभावित दिशाओं में से एक में मैट्रिक्स के साथ एक कदम पुरानी लाइन पर कार्रवाई है:
- क्षैतिज चरण - पुरानी लाइन से हटाएं
- वर्टिकल स्टेप - पुरानी लाइन में जोड़ें
- विकर्ण कदम - कोई बदलाव नहीं
एक उदाहरण के रूप में दूसरे पथ का उपयोग करते हुए, हम पथ और परिणामी स्क्रिप्ट की तुलना करते हैं। पहला चरण ऊर्ध्वाधर है, जिसका अर्थ है कि हम वर्ण "C" को पुरानी पंक्ति में 0 स्थिति में जोड़ते हैं।

हालांकि, यह पूरा सांप नहीं है। अगला, हमें तिरछे चलना चाहिए। तिरछे चलते समय, तत्व B अपरिवर्तित रहता है। नतीजतन, सांप में ऊर्ध्वाधर आंदोलन + विकर्ण आंदोलन होते हैं।

अगला, सांप क्षैतिज रूप से - तत्व ए को पुरानी रेखा से हटा दें

वीडियो स्रोत से स्ट्रिंग में अंतिम छोर तक परिवर्तित होने तक शुरू से अंत तक पूरे रास्ते को दिखाता है।

मायर्स एल्गोरिदम का परिणाम एक स्क्रिप्ट है जिसमें न्यूनतम संख्या में क्रियाएं होती हैं जिन्हें एक अनुक्रम को दूसरे में बदलने के लिए किया जाना चाहिए। DiffUtil
मायर्स एल्गोरिथ्म का उपयोग विभिन्न तत्वों की खोज करने के लिए किया जाता है जो areItemsTheSame()
विधि द्वारा निर्धारित किए जाते हैं। सांपों की सूची बनाने के अलावा, जब सूचियों से गुजरते हुए, मायर्स एल्गोरिथ्म पुरानी और नई सूचियों के तत्वों की स्थिति की सूची बनाता है। यह सब डेटा, साथ ही detectMoves
फ्लैग और यूज़र द्वारा लागू कॉलबैक, DiffResult(Callback callback, List<Snake> snakes, int[] oldItemStatuses, int[] newItemStatuses, boolean detectMoves)
कंस्ट्रक्टर DiffResult(Callback callback, List<Snake> snakes, int[] oldItemStatuses, int[] newItemStatuses, boolean detectMoves)
।
जब मैं इस लेख को लिख रहा था, तो मैं यह पता लगाने में सक्षम था कि वास्तव में DiffResult
में क्या हो रहा है: एल्गोरिथ्म सांपों के माध्यम से जाता है और तत्वों को झंडे सेट करता है (स्थिति सूचियों में), जो निर्धारित करता है कि तत्व का वास्तव में क्या हुआ है। इन झंडों का उपयोग करते हुए, RecyclerView
परिवर्तन लागू करते समय RecyclerView
निर्धारित किया जाता है कि अद्यतन करने के लिए कौन सी विधि है: notifyItemRangeInserted, notifyItemRangeRemoved, notifyItemMoved notifyItemRangeChanged
। अगली बार मैं इस बारे में विस्तार से बात करूंगा।
संदर्भ