android - व्यूहोल्डर का क्या फायदा है?




listview android-arrayadapter (3)

जब आप एक एंड्रॉइड प्रोग्राम विकसित कर रहे हैं; और आप एक ऐरेएडाप्टर चाहते हैं, तो आप बस एक कक्षा ( व्यूहोल्डर प्रत्यय के साथ अधिकतर बार) कर सकते हैं या सीधे अपने कन्वर्ट व्यू को बढ़ा सकते हैं और आईडी द्वारा अपना दृश्य ढूंढ सकते हैं।
तो ViewHolder का उपयोग करने का क्या फायदा है?
यहां दोनों का उदाहरण:

        if(convertView==null)
        {
            convertView = ((Activity)_context).getLayoutInflater().inflate(R.layout.row_phrase, null);
        }
((TextView)convertView.findViewById(R.id.txtPhrase)).setText("Phrase 01");  

या:

static class ViewHolder {   
ImageView leftIcon;   
TextView upperLabel;  
TextView lowerLabel;  
}

और अंत में getView में:

ViewHolder holder = null;
  if (view == null) {
   view = LayoutInflater.from(context).inflate(R.layout.row_layout,
   null, false);
   holder = new ViewHolder();
   holder.leftIcon = (ImageView) view.findViewById(R.id.leftIcon);

जैसे ही आप अपनी लिस्ट व्यू के माध्यम से बहते हैं, किसी भी समय दिए गए कुछ मुट्ठी दिखाए जा रहे हैं। इसका मतलब है कि आपको अपने एडाप्टर में प्रत्येक आइटम के लिए दृश्य को तुरंत चालू करने की आवश्यकता नहीं है; जब एक दृश्य ऑफ-स्क्रीन स्क्रॉल करता है, तो इसका पुन: उपयोग किया जा सकता है, या पुनर्नवीनीकरण किया जा सकता है

रीसाइक्लिंग देखें और व्यूहोल्डर पैटर्न समान नहीं हैं। ViewHolder पैटर्न पूरी तरह से view.findViewById(int) कॉल की संख्या को कम करने के लिए है। व्यूहोल्डर पैटर्न केवल तभी काम करता है जब आप व्यू रीसाइक्लिंग का लाभ उठाते हैं।

getView(int position, View convertView, ViewGroup parent) , convertView पैरामीटर या तो शून्य है या यह एक ऐसा दृश्य है जिसे पुनर्नवीनीकरण किया गया है: इसमें अभी भी एक अलग सूची आइटम से डेटा होगा।

व्यूहोल्डर पैटर्न के बिना, आप अभी भी दृश्य रीसाइक्लिंग का लाभ उठा सकते हैं (यानी अंधेरे से तत्काल विचार नहीं):

public View getView(int position, View convertView, ViewGroup parent) {
  View view = convertView;
  if (view == null) {
    view = // inflate new view
  }

  ImageView imageView = (ImageView) view.findViewById(R.id.listitem_image);
  TextView textView = (TextView) view.findViewById(R.id.listitem_text);
  TextView timestampView = (TextView) view.findViewById(R.id.listitem_timestamp);
  ProgressBar progressSpinnerView = (ProgressBar) view.findViewById(R.id.progress_spinner);

  // TODO: set correct data for this list item
  // imageView.setImageDrawable(...)
  // textView.setText(...)
  // timestampView.setText(...)
  // progressSpinnerView.setProgress(...)

  return view;
}

ऊपर रीसाइक्लिंग देखने का एक उदाहरण है - हम प्रत्येक पंक्ति के लिए एक नया दृश्य नहीं बढ़ाते हैं; अगर हम किसी को पुन: उपयोग करने के लिए नहीं दिए जाते हैं तो हम केवल एक दृश्य बढ़ाते हैं। दृश्य को बढ़ाने से बचने का वह हिस्सा है जो आपकी सूची के माध्यम से स्क्रॉल करते समय प्रदर्शन के साथ निश्चित रूप से सहायता करेगा: दृश्य रीसाइक्लिंग का लाभ उठाएं।

तो, फिर के लिए व्यूहोल्डर क्या है? हम वर्तमान में प्रत्येक आइटम के लिए 4x findViewById(int) कर रहे हैं, इस पर ध्यान दिए बिना कि पंक्ति पहले से मौजूद है या नहीं। जैसा कि findViewById(int) एक findViewById(int) टिल को दोबारा शुरू करता है, यह दिए गए आईडी के साथ एक वंशज को पाता है, यह हमारे पुनर्नवीनीकरण विचारों के लिए थोड़ा सा व्यर्थ है - हम उन विचारों को फिर से ढूंढ रहे हैं जिनके पास हमारे पास पहले से संदर्भ हैं।

उपरोक्त दृश्यों के संदर्भों को पकड़ने के बाद व्यूहोल्डर ऑब्जेक्ट का उपयोग करके इसे "ढूंढें" के बाद इसे से बचें:

private static class ViewHolder {
  final TextView text;
  final TextView timestamp;
  final ImageView icon;
  final ProgressBar progress;

  ViewHolder(TextView text, TextView timestamp, ImageView icon, ProgressBar progress) {
    this.text = text;
    this.timestamp = timestamp;
    this.icon = icon;
    this.progress = progress;
  }
}

View.setTag(Object) आपको एक मनमानी ऑब्जेक्ट को पकड़ने के लिए दृश्य को बताने की अनुमति देता है। यदि हम अपने findViewById(int) कॉल करने के बाद हमारे findViewById(int) का उदाहरण रखने के लिए इसका उपयोग करते हैं, तो हम बार-बार कॉल करने से बचने के लिए रीसाइक्लिंग दृश्यों पर View.getTag() उपयोग कर सकते हैं।

public View getView(int position, View convertView, ViewGroup parent) {
  View view = convertView;
  if (view == null) {
    view = // inflate new view
    ViewHolder holder = createViewHolderFrom(view);
    view.setTag(holder);  
  }
  ViewHolder holder = view.getTag();
  // TODO: set correct data for this list item
  // holder.icon.setImageDrawable(...)
  // holder.text.setText(...)
  // holder.timestamp.setText(...)
  // holder.progress.setProgress(...)
  return view;
}

private ViewHolder createViewHolderFrom(View view) {
    ImageView icon = (ImageView) view.findViewById(R.id.listitem_image);
    TextView text = (TextView) view.findViewById(R.id.listitem_text);
    TextView timestamp = (TextView) view.findViewById(R.id.listitem_timestamp);
    ProgressBar progress = (ProgressBar) view.findViewById(R.id.progress_spinner);

    return new ViewHolder(text, timestamp, icon, progress);
}

इस अनुकूलन के प्रदर्शन लाभ संदिग्ध हैं , लेकिन यह व्यूहोल्डर का लाभ है


पहले तो :

ListView जब आप ListView स्क्रॉल करते हैं तो आपको नया आइटम बनाने और उसके डेटा को बाध्य करने की आवश्यकता होती है, इसलिए यदि आपके पास ListView में बहुत अधिक आइटम हैं तो यह स्मृति रिसाव का कारण बन सकता है क्योंकि आपके द्वारा आइटम्स के लिए बनाए गए अधिक ऑब्जेक्ट्स, लेकिन एंड्रॉइड के अधिकांश एपीआई रीसायकल की अवधारणा का उपयोग करते हुए एंड्रॉइड , और इसका मतलब है कि आप एक ऑब्जेक्ट बनाते हैं और इसे नष्ट करने और नए घोषित करने के बजाए इसका उपयोग करते हैं, इसलिए जब आप स्क्रॉल किए गए अदृश्य आइटमों का उपयोग करके ListView API को स्क्रॉल करते हैं और इसे प्राप्त करने के लिए इसे पास करते हैं तो getView विधि में यह convertView तो यहां देखें और अधिक आइटम से निपटें ListView

दूसरा:

यदि आपके पास ListView में कस्टम आइटम है तो आपको ListView प्रत्येक आइटम पर अपना कस्टम लेआउट संलग्न करने की आवश्यकता है ताकि आप प्रत्येक बार ListView लेआउट आइटम्स का संदर्भ प्राप्त करने के लिए findViewById का उपयोग करके नए आइटम को findViewById । यह विधि आपके आइटम को रिकर्सिव तरीके से खोजने के लिए जाएगी ताकि आप ViewHolder केवल एक बार के लिए रिकर्सिव करने में मदद कर सकें और फिर यह आपके लिए लेआउट आइटम का संदर्भ रखेगा जब तक कि आप इसे ListView लिए संलग्न नहीं कर लेते

उम्मीद है कि यह आपकी मदद करेगा और किसी भी स्पष्ट चीज़ में मुझे वापस खिलाएगा


ViewHolder डिज़ाइन पैटर्न का उपयोग आपकी लिस्ट व्यू के प्रतिपादन को तेज़ करने के लिए किया जाता है - असल में इसे आसानी से काम करने के लिए, ढूंढें ViewById काफी महंगा है (यह डोम पार्सिंग करता है) जब प्रत्येक बार एक सूची आइटम प्रदान किया जाता है, तो इसे आपके लेआउट पदानुक्रम को पार करना होगा और वस्तुओं को तुरंत चालू करना होगा । चूंकि सूचियां इस तरह के ओवरहेड को स्क्रॉल करने के दौरान अक्सर अपने सामान को फिर से खींचा जा सकता है, यह पर्याप्त हो सकता है।

आप इस बारे में अच्छी व्याख्या कर सकते हैं कि यह कैसे काम करता है:

http://www.youtube.com/watch?v=wDBM6wVEO70&feature=youtu.be&t=7m

10 मिनट से शुरू, आपने Google विशेषज्ञों द्वारा व्यूहोल्डर डिजाइन पैटर्न को समझाया है।

[संपादित करें]

findViewById नई ऑब्जेक्ट्स को तुरंत चालू नहीं कर रहा है, यह केवल पदानुक्रमों को पार करता है - यहां संदर्भ है http://androidxref.com/5.1.1_r6/xref/frameworks/base/core/java/android/view/ViewGroup.java#3610







android-viewholder