RecyclerView.ViewHolder - getLayoutPosition बनाम getAdapterPosition


90

नए समर्थन लाइब्रेरी संस्करण (22.x) के बाद से विषय में वर्णित विधियों के बदले वर्ग की getPosition()विधि RecyclerView.ViewHolderको हटा दिया गया है। मुझे डॉक्स पढ़ने से वास्तव में फर्क नहीं पड़ता। क्या कोई आम आदमी की शर्तों में अंतर समझा सकता है?

मेरे पास निम्नलिखित उपयोग का मामला है - मैं अपने एडेप्टर को एक देता हूं List, और प्रत्येक सूची आइटम के लिए अतिरिक्त जानकारी को जोड़ने में सक्षम होना चाहता हूं। मेरे पास स्थिति-से-अतिरिक्त मानचित्रण है, और धारकों के लिए मानचित्रण उपलब्ध है ताकि वे अपनी स्थिति के लिए अतिरिक्त ला सकें और इसके साथ सामान कर सकें। धारक में, मुझे किस विधि का उपयोग करना चाहिए?

धारक के साथ क्या होता है जब सूचकांक 0 और 1 पर सूची आइटम स्विच किए गए स्थान हैं? क्या तरीके वापस आते हैं?

जवाबों:


116

यह एक मुश्किल स्थिति है, क्षमा करें कि डॉक्स पर्याप्त नहीं हैं।

जब एडेप्टर सामग्री बदल जाती है (और आप कॉल करते हैं notify***()) RecyclerView एक नए लेआउट का अनुरोध करता है। उस क्षण से, जब तक कि लेआउट सिस्टम एक नए लेआउट (<16 एमएस) की गणना करने का निर्णय नहीं लेता है, तब तक लेआउट की स्थिति और एडेप्टर की स्थिति मेल नहीं खा सकती है क्योंकि लेआउट ने अभी तक एडेप्टर परिवर्तन को प्रतिबिंबित नहीं किया है।

आपके उपयोग के मामले में, चूंकि आपका डेटा आपकी एडॉप्टर सामग्री से संबंधित है (और मुझे लगता है कि एडॉप्टर परिवर्तनों के साथ डेटा उसी समय बदल जाता है), आपको उपयोग करना चाहिए adapterPosition

हालांकि, यदि आप कॉल कर रहे हैं, तो सावधान रहें notifyDataSetChanged(), क्योंकि यह सब कुछ अमान्य करता है, RecyclerView को पता नहीं है कि अगले लेआउट की गणना होने तक ViewHolder के एडाप्टर की स्थिति क्या है। उस स्थिति में, getAdapterPosition()वापस आ जाएगी RecyclerView#NO_POSITION( -1)।

लेकिन अगर आपने कहा है notifyItemInserted(0), तो getAdapterPosition()ViewHolder की स्थिति जो पहले थी, 0उसे 1तुरंत वापस करना शुरू कर देगा । तो जब तक आप दानेदार सूचनाओं को भेज रहे हैं, आप हमेशा अच्छी स्थिति में होते हैं (हम एडेप्टर की स्थिति जानते हैं, हालांकि नए लेआउट की गणना अभी तक नहीं की गई है)।

एक अन्य उदाहरण, यदि आप उपयोगकर्ता क्लिक पर कुछ कर रहे हैं, यदि getAdapterPosition()रिटर्न देता है NO_POSITION, तो उस क्लिक को अनदेखा करना सबसे अच्छा है क्योंकि आप नहीं जानते कि उपयोगकर्ता ने क्या क्लिक किया (जब तक कि आपके पास कोई अन्य तंत्र नहीं है, जैसे आइटम देखने के लिए स्थिर आईडी)।

जब लेआउट की स्थिति अच्छी हो तो संपादित करें

कहते हैं कि आप उपयोग कर रहे हैं LinearLayoutManagerऔर वर्तमान में क्लिक की गई वस्तु के ऊपर ViewHolder को एक्सेस करना चाहते हैं। उस स्थिति में, आपको आइटम को ऊपर लाने के लिए लेआउट स्थिति का उपयोग करना चाहिए।

mRecyclerView.findViewHolderForLayoutPosition(myViewHolder.getLayoutPosition() - 1)

आपको लेआउट स्थिति का उपयोग करना होगा क्योंकि यह मेल खाता है कि उपयोगकर्ता वर्तमान में स्क्रीन पर क्या देख रहा है।


1
मैं थोड़ा सा आसपास खेला और यह getAdapterPosition () विधि हमेशा मुझ पर -1 देता है। मैंने इसे डीबग किया और इसका कारण यह है कि विधि में कोड (अंतिम ViewParent पेरेंट = itemView.getPent ();) यदि ((पेरेंट इंस्टाफॉरेक्स्ट व्यू)) {रिटर्न -1;} हमेशा इफ़ेक्ट, अर्थात रिसाइक्लर व्यू में मिलता है। मेरे सेल व्यू का जनक नहीं है। यह कैसे हो सकता है? धारक बनाने के लिए मेरा कोड है: MyViewHolder (LayoutInflater.from (viewGroup.getContext ())। inflate (R.layout.est_list_item, viewGroup, false))। (एक अन्य टिप्पणी में जारी है।)
वुजेक

जब मैं कॉल करने के लिए कोड को बदल कर फुलाया (R.layout.test_list_item, viewGroup, true); ('अटैच टू रूट) पर ध्यान दें, Android फेंकता है: java.lang.IllegalStateException: निर्दिष्ट बच्चे के पास पहले से ही एक माता-पिता हैं। आपको पहले बच्चे के माता-पिता पर निष्कासन () देखना होगा। तो एक दृश्य धारक के साथ एक दृश्य धारक बनाने का सही तरीका क्या है जो पुनर्नवीनीकरण दृश्य से सही तरीके से जुड़ा हुआ है? बहुत अजीब है, भले ही getAdapterPosition () रिटर्न -1 है क्योंकि माता-पिता अशक्त हैं, बाकी सब ठीक काम करता है।
वुजेक

1
लेआउट इनफ़्लोटर में बूलियन पैरामीटर "addToParent" है। यह गलत होना चाहिए क्योंकि इसे जोड़ने के लिए LayoutManager की जिम्मेदारी है। मुझे लगता है कि आप onBind में getAdapterPosition कह रहे हैं, जहां आप पहले से ही स्थिति में हैं। तकनीकी रूप से, व्यू होल्डर ऑन रिटर्न के बाद उस स्थिति का प्रतिनिधित्व करता है। Btw, हमने एक वैध स्थिति (यदि संभव हो तो) को अलग कर दिया है, भले ही इसे अलग कर दिया है, इसे वापस करने के लिए getAdapter स्थिति अपडेट की गई है।
यजीत

आप सही हैं, मैं onBind में getAdapterPosition कह रहा हूं। इस मामले में मुझे क्या करना चाहिए इसके बजाय, मुझे कुछ जानकारी प्राप्त करने के लिए स्थिति की आवश्यकता है जो कुछ विचारों की स्थिति को प्रभावित करती है। क्या इस मामले में getLayoutPosition कॉल करना ठीक है?
वुजेक

5
आपको उस पोजीशन पैरामीटर का उपयोग करना चाहिए जो onBind विधि से पास किया गया है।
यजीत

2


आदेश अंतर (ओं) की बहस करने में getAdapterPosition(), getLayoutPosition()और साथ ही position, हम नीचे के मामलों को नोटिस करेंगे:

1. विधि positionमें तर्क onBindViewHolder():

हम positionडेटा को देखने के लिए बाइंड करने के लिए उपयोग कर सकते हैं और ऐसा करने के लिए positionतर्क का उपयोग करना ठीक है, लेकिन positionउपयोगकर्ता क्लिकों को संभालने के लिए तर्क का उपयोग करना ठीक नहीं है और यदि आपने इसका उपयोग किया है तो आपको एक चेतावनी दिखाई देगी "के positionरूप में इलाज करने के लिए नहीं" holder.getAdapterPosition()इसके बजाय निश्चित और उपयोग करें ”।

2 getAdapterPosition().:

इस पद्धति में हमेशा अपडेट किए गए एडॉप्टर की स्थिति होती है holder। इसका मतलब है कि जब भी आप किसी आइटम पर क्लिक करते हैं, तो आप एडॉप्टर से इसके बारे में पूछते हैं position। इसलिए आपको एडॉप्टर के तर्क के संदर्भ में इस आइटम की नवीनतम स्थिति मिल जाएगी।

3 getLayoutPosition().:

कभी-कभी, positionअपडेट किए गए लेआउट (उपयोगकर्ता द्वारा अब देखा जा रहा अंतिम लेआउट) के संदर्भ में इसे खोजने की आवश्यकता है , उदाहरण के लिए: यदि उपयोगकर्ता तीसरे के लिए पूछता है तो positionवह देख सकता है और आप आइटमों के लिए swipe/ उपयोग dismissकरते हैं या कोई एनीमेशन लागू करते हैं या वस्तुओं के लिए सजावट getLayoutPosition()इसके बजाय उपयोग करना बेहतर होगा getAdapterPosition(), क्योंकि आप हमेशा सुनिश्चित करेंगे कि आप नवीनतम पारित लेआउट के संदर्भ में आइटम की स्थिति से निपट रहे हैं।


इस बारे में अधिक जानकारी के लिए; यहाँ देखें । । ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.