2012-09-24 12 views
23

में setImageBitmap() सेट करते समय getView (position == 0) को लेआउट को मापने के लिए कई बार बुलाया गया था, मेरे पास कुछ आइकन दिखाने के लिए GridView है।ग्रिडव्यू एडाप्टर में, लोडव्यू

से पहले मैं Android डेवलपर साइट से इस Displaying Bitmaps Efficiently पढ़ा था, मैं एडाप्टर के getView() में सीधे स्थानीय पथ से बिटमैप डिकोडिंग किया गया था, इस तरह:

public View getView(int position, View convertView, ViewGroup parent) { 
     ... 
     ImageView icon = ...... (from getTag() of convertView) 
     icon.setImageBitmap(BitmapUtil.decode(iconPath)); 
     ... 
} 

इस तरह से ठीक काम करता है वैसे भी, मैं इसे [प्रत्यक्ष मोड कहा जाता ], getView() विधि के लिए उत्पादन लॉग होना चाहिए:

getView(0) // measure kid's layout. 
getView(0) 
getView(1) 
getView(2) 
... 
getView(n)  // when scrolling gridview. 
getView(n+1) 
... 
getView(n+3) // scrolling again. 
getView(n+4) 
... 

तो मैं निम्नलिखित के रूप में, लेख Displaying Bitmaps Efficiently में उल्लेख किया [लोडर मोड] के लिए कोड बदलने की कोशिश कर रहा हूँ:

public View getView(int position, View convertView, ViewGroup parent) { 
     ... 
     ImageView icon = ...... (from getTag() of convertView) 
     loadIcon(icon, iconPath); 
     ... 
} 
loadIcon() में

:

... 
final CacheImageLoader loader = new CacheImageLoader(getActivity(), imageView, imageUrl, savePath); 
final AsyncDrawable asyncDrawable = new AsyncDrawable(getResources(), placeHolderBitmap, loader); 
imageView.setImageDrawable(asyncDrawable); 
लोडर के श्रोता में

:

@Override 
public void onLoadComplete(Loader<Bitmap> arg0, Bitmap arg1) { 
    ... 
    ImageView imageView = imageViewReference.get(); 
    if (result != null && imageView != null) { 
     imageView.setImageBitmap(result); 
    } 
} 

असल में, यह प्रशिक्षण कोड के रूप में ही है, वास्तव में, इस तरह से काम करता है ठीक भी है। हालांकि, मुझे कुछ अलग मिला, इस मोड में getView() एडाप्टर में विधि को कई बार बुलाया गया था, हालांकि, इन पद्धतियों को हमेशा "स्थिति" पैरामीटर == 0 के साथ दोहराया जाता है, इसका मतलब है कि कुछ बार बार etView(0, X, X) का आह्वान करता है।

getView(0)  // measure kid's layout. 
getView(0) 
getView(1) 
getView(2) 
...  
getView(0)  // loader completed then imageView.setImageBitmap(result); 
getView(0)  // same as above 
getView(0) 
getView(0) 
... 
getView(n)  // when scrolling gridview. 
getView(n+1) 
getView(n+2) 
getView(0)  // loader completed then imageView.setImageBitmap(result); 
getView(0)  // same as above 
getView(0) 
... 
getView(n+3) // scrolling again. 
getView(n+4) 
getView(0)  // loader completed then imageView.setImageBitmap(result); 
getView(0)  // same as above 
getView(0) 

यह अच्छा है क्योंकि मैं getView() में एक लोडर उपयोग कर रहा हूँ नहीं है। मैं स्रोत कोड की जाँच की है और पाया है कि वे मूल रूप से लोडर के onLoadComplete विधि में imageView.setImageBitmap(result) द्वारा कहा जाता है और ImageView में:

/** 
* Sets a drawable as the content of this ImageView. 
* 
* @param drawable The drawable to set 
*/ 
public void setImageDrawable(Drawable drawable) { 
     ... 

     int oldWidth = mDrawableWidth; 
     int oldHeight = mDrawableHeight; 

     updateDrawable(drawable); 

     if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) { 
      requestLayout(); 
     } 
     invalidate(); 
    } 
} 
यहाँ

, requestLayout() देखें की विधि है और हमेशा या तो [प्रत्यक्ष मोड] में कार्यान्वित या [लोडर मोड], View.class में:

public void requestLayout() { 
    mPrivateFlags |= FORCE_LAYOUT; 
    mPrivateFlags |= INVALIDATED; 

    if (mLayoutParams != null) { 
     mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection()); 
    } 

    if (mParent != null && !mParent.isLayoutRequested()) { 
     mParent.requestLayout(); 
    } 
} 

तथापि अंतर है: [प्रत्यक्ष मोड] में, mParent.requestLayout() एक बार लागू है, लेकिन में [लोडर मोड] है, हर समय था जब मैं फोन imageView.setImageBitmap(result);, mParent.requestLayout() यह mParent.isLayoutRequested() वापसी false का मतलब है और साथ ही लागू किया जाएगा, और mParent.requestLayout(); पहले बच्चे को obtainView() फोन करके GridView उपाय है अपने बच्चे के लेआउट का कारण और उसके बाद का कारण होगा getView(0, X, X):

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    ... 
    mItemCount = mAdapter == null ? 0 : mAdapter.getCount(); 
    final int count = mItemCount; 
    if (count > 0) { 
     final View child = obtainView(0, mIsScrap); 
    ... 

तो, मेरा प्रश्न है: क्यों mParent.isLayoutRequested() वापसी false यदि मैं [लोडर मोड] का उपयोग कर रहा हूं? या यह सिर्फ एक सामान्य मामला है?

+0

जहां तक ​​मुझे पता है कि यह सामान्य है, एंड्रॉइड किसी भी समय आपके एडाप्टर की किसी भी विधि को कॉल कर सकता है और जितनी बार पसंद करता है। यह संस्करण से संस्करण में भी भिन्न होता है। इसके बारे में कभी भी कुछ न मानें। 'GridView'' ListView' के समान है, इसलिए इस महान बात को देखें http://www.youtube.com/watch?v=wDBM6wVEO70। जब तक आपको कुछ क्रैश या स्मृति कम त्रुटि न हो, तब तक इसके बारे में चिंता न करें और इसे अपनी विधियों को कॉल न करें। और हाँ [लोडर मोड] में एंड्रॉइड बाद में GUI को रीफ्रेश करेगा जब भी ऑनलोड लोड() कहा जाता है। –

+0

"सेटिंग्स> डेवलपर विकल्प> लेआउट अपडेट दिखाएं" की जांच करें और अपना ऐप लॉन्च करें। यदि आपके सभी लोडर समाप्त होने पर जीयूआई बस जाता है तो आप जाने के लिए अच्छे हैं। –

+1

क्या आपको इसके आसपास कोई रास्ता मिला? मुझे यह भी मिलता है। – Matthias

उत्तर

7

isLayoutRequested बस आपको यह बताने के लिए है कि क्या View के लिए कोई लेआउट पहले ही लंबित है या नहीं। यही है, requestLayout के बाद, isLayoutRequested अगले लेआउट पास पूरा होने तक सत्य वापस आ जाएगा। requestLayout में इस चेक का एकमात्र कारण माता-पिता पर बार-बार requestLayout पर कॉल करना है, यदि यह वैसे भी लेआउट करने वाला है। isLayoutRequested यहां एक लाल हेरिंग है: यह onMeasure का बार-बार कहा जाने का कारण नहीं है।

मूल समस्या यह है कि ImageView जब भी आप अपना ड्रायबल बदलते हैं तो एक नया लेआउट अनुरोध करता है। यह दो कारणों से जरूरी है: -

  1. छवि दृश्य का आकार ड्रॉ करने योग्य पर निर्भर हो सकता है, अगर adjustViewBounds सेट है। यह लेआउट के आधार पर अन्य विचारों के आकार को प्रभावित कर सकता है: ImageView में आपके पास पर्याप्त जानकारी नहीं है।
  2. ImageView.onMeasure स्केल मोड के अनुसार ImageView की सीमाओं में फ़िट होने के लिए कितना आकर्षित करने योग्य आकार बदलने के लिए ज़िम्मेदार है। यदि नया ड्रॉबल पुराना ड्रॉबल के समान आकार नहीं है, तो ImageView आवश्यक स्केलिंग को फिर से सम्मिलित करने के लिए फिर से मापा जाना चाहिए।

आप केवल लोडर द्वारा Bitmap एस के स्थानीय कैश को रखकर बहुत अधिक लोडर होने की समस्या को ठीक कर सकते हैं। कैश में Bitmap एस हो सकता है यदि आपको पता है कि बहुत से लोग नहीं हैं, या केवल n हाल ही में उपयोग किए गए हैं। अपने getView में, पहले जांचें कि उस आइटम के लिए Bitmap कैश में मौजूद है, और यदि ऐसा है, तो ImageView पहले से ही उस Bitmap पर सेट करें। केवल अगर यह कैश में नहीं है तो आपको लोडर का उपयोग करने की आवश्यकता है।

सावधान: अंतर्निहित डेटा को बदल सकते हैं, तो अब आपको GridView पर invalidate बुला या ContentResolver के माध्यम से यह सूचना देने के रूप में एक ही समय में कैश रद्द करने के लिए सुनिश्चित करने के लिए की जरूरत है। मैंने अपने ऐप में इसे प्राप्त करने के लिए कुछ होमब्रू कोड का उपयोग किया है, और यह मेरे लिए अच्छी तरह से काम करता है, लेकिन स्क्वायर के अच्छे लोगों के पास आपकी पसंद के लिए सभी कड़ी मेहनत करने के लिए Picasso नामक एक ओपन-सोर्स लाइब्रेरी है।

1

यह सामान्य व्यवहार है, एंड्रॉइड एक ही स्थिति के लिए getView को कई बार कॉल कर सकता है। यह आवश्यक होने पर केवल getView में थंबनेल प्राप्त करने/सेट करने के लिए डेवलपर पर है (यानी अगर थंबनेल सेट नहीं किया गया था या थंबनेल पथ में परिवर्तन आया है)। अन्य मामलों में बस कनवर्ट व्यू वापस करें, जिसे हम getView में पैरामीटर के रूप में प्राप्त करते हैं।

0

ऊंचाई के संदर्भ में किसी भी स्थान पर अपने एक्सएमएल लेआउट को समायोजित करने का प्रयास करें, क्योंकि एंड्रॉइड प्रत्येक बार आकर्षित करने के लिए एक उपाय करेगा और फिर से सेल को फिर से खींचा जाएगा। सूचीदृश्य match_parent और सेल पर एक बिल्कुल ऊंचाई पर सेल पर उपयोग करने का प्रयास करें। क्षमा करें मेरी खराब अंग्रेजी।

1

मुझे एक ही समस्या थी। ग्रिड हमेशा अपने पहले बच्चे को माप रहा है, भले ही मैं 30 स्थिति में हूं।
मैं सिर्फ getView शीर्ष में इस चेक जोड़कर पूरे getView कोड बाईपास:

@Override 
public View getView(final int position, View convertView, ViewGroup parent) { 
    // Patch for multiple getView for position 0 
    if(convertView!=null && position==0 && viewGrid.getFirstVisiblePosition()>1) return convertView; 

यह बंद नहीं getView बुलाया जा रहा है, लेकिन कम से कम ग्रंथों, छवियों और लेआउट में डॉन 'टी रन बदल जाता है।

+0

यदि आपके पास प्रति पंक्ति एक से अधिक आइटम हो सकते हैं, तो प्रति पंक्ति में अधिकतम संख्या के साथ "1" बदलें। – Anthony

संबंधित मुद्दे