Note that there are some explanatory texts on larger screens.

plurals
  1. POIn gridview adapter, getView(position == 0) was invoked too many times to measure layout when setImageBitmap() in a loader
    text
    copied!<p>I have a <code>GridView</code> for showing some icons.</p> <p>BEFORE I had read this <a href="http://developer.android.com/training/displaying-bitmaps/index.html" rel="nofollow noreferrer">Displaying Bitmaps Efficiently</a> from Android developer site, I was decoding bitmap from local path directly in <code>getView()</code> of adapter, like this :</p> <pre><code>public View getView(int position, View convertView, ViewGroup parent) { ... ImageView icon = ...... (from getTag() of convertView) icon.setImageBitmap(BitmapUtil.decode(iconPath)); ... } </code></pre> <p>this way works fine anyway, I called it [Direct Mode], the output log for <code>getView()</code> method should be :</p> <pre><code>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) ... </code></pre> <p>then I am trying to change the code to [Loader Mode] mentioned in article <a href="http://developer.android.com/training/displaying-bitmaps/index.html" rel="nofollow noreferrer">Displaying Bitmaps Efficiently</a>, as following :</p> <pre><code>public View getView(int position, View convertView, ViewGroup parent) { ... ImageView icon = ...... (from getTag() of convertView) loadIcon(icon, iconPath); ... } </code></pre> <p>in <code>loadIcon()</code> :</p> <pre><code>... final CacheImageLoader loader = new CacheImageLoader(getActivity(), imageView, imageUrl, savePath); final AsyncDrawable asyncDrawable = new AsyncDrawable(getResources(), placeHolderBitmap, loader); imageView.setImageDrawable(asyncDrawable); </code></pre> <p>in Loader's listener :</p> <pre><code>@Override public void onLoadComplete(Loader&lt;Bitmap&gt; arg0, Bitmap arg1) { ... ImageView imageView = imageViewReference.get(); if (result != null &amp;&amp; imageView != null) { imageView.setImageBitmap(result); } } </code></pre> <p>Basically, it is same as the training code, actually, this way works fine as well. However, I found something different, in this mode the <code>getView()</code> method in adapter was invoked too many times, however, these repeat call to this method always with "position" parameter == 0, it means something invoke g<code>etView(0, X, X)</code> repeatedly. </p> <pre><code>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) </code></pre> <p>It is not good because I am using a loader in <code>getView()</code>. I have checked the source code and found they are originally called by <strong><code>imageView.setImageBitmap(result)</code></strong> in loader's <code>onLoadComplete</code> method, and in <code>ImageView</code> :</p> <pre><code> /** * 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(); } } </code></pre> <p>here, <strong><code>requestLayout()</code></strong> is View's method and always executes in either [Direct Mode] or [Loader Mode], in View.class :</p> <pre><code>public void requestLayout() { mPrivateFlags |= FORCE_LAYOUT; mPrivateFlags |= INVALIDATED; if (mLayoutParams != null) { mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection()); } if (mParent != null &amp;&amp; !mParent.isLayoutRequested()) { mParent.requestLayout(); } } </code></pre> <p>however the difference is: in [Direct Mode], the <code>mParent.requestLayout()</code> is invoked once, but in [Loader Mode], every time when i call <strong><code>imageView.setImageBitmap(result);</code></strong>, the <code>mParent.requestLayout()</code> will be invoked as well, it means <code>mParent.isLayoutRequested()</code> return <code>false</code>, and <code>mParent.requestLayout();</code> will cause the <code>GridView</code> measure its kid's layout by calling <code>obtainView()</code> to first kid and then cause <code>getView(0, X, X)</code> :</p> <pre><code>@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ... mItemCount = mAdapter == null ? 0 : mAdapter.getCount(); final int count = mItemCount; if (count &gt; 0) { final View child = obtainView(0, mIsScrap); ... </code></pre> <hr> <p>So, my <strong>question</strong> is: why <code>mParent.isLayoutRequested()</code> return <code>false</code> if I am using [loader mode]? or is it just a normal case ? </p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload