I have a GridView
for showing some icons.
BEFORE I had read this Displaying Bitmaps Efficiently from Android developer site, I was decoding bitmap from local path directly in getView()
of adapter, like this :
public View getView(int position, View convertView, ViewGroup parent) {
...
ImageView icon = ...... (from getTag() of convertView)
icon.setImageBitmap(BitmapUtil.decode(iconPath));
...
}
this way works fine anyway, I called it [Direct Mode], the output log for getView()
method should be :
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)
...
then I am trying to change the code to [Loader Mode] mentioned in article Displaying Bitmaps Efficiently, as following :
public View getView(int position, View convertView, ViewGroup parent) {
...
ImageView icon = ...... (from getTag() of convertView)
loadIcon(icon, iconPath);
...
}
in loadIcon()
:
...
final CacheImageLoader loader = new CacheImageLoader(getActivity(), imageView, imageUrl, savePath);
final AsyncDrawable asyncDrawable = new AsyncDrawable(getResources(), placeHolderBitmap, loader);
imageView.setImageDrawable(asyncDrawable);
in Loader's listener :
@Override
public void onLoadComplete(Loader<Bitmap> arg0, Bitmap arg1) {
...
ImageView imageView = imageViewReference.get();
if (result != null && imageView != null) {
imageView.setImageBitmap(result);
}
}
Basically, it is same as the training code, actually, this way works fine as well. However, I found something different, in this mode the getView()
method in adapter was invoked too many times, however, these repeat call to this method always with "position" parameter == 0, it means something invoke getView(0, X, X)
repeatedly.
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)
It is not good because I am using a loader in getView()
. I have checked the source code and found they are originally called by imageView.setImageBitmap(result)
in loader's onLoadComplete
method, and in 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();
}
}
here, requestLayout()
is View's method and always executes in either [Direct Mode] or [Loader Mode], in View.class :
public void requestLayout() {
mPrivateFlags |= FORCE_LAYOUT;
mPrivateFlags |= INVALIDATED;
if (mLayoutParams != null) {
mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection());
}
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
}
however the difference is: in [Direct Mode], the mParent.requestLayout()
is invoked once, but in [Loader Mode], every time when i call imageView.setImageBitmap(result);
, the mParent.requestLayout()
will be invoked as well, it means mParent.isLayoutRequested()
return false
, and mParent.requestLayout();
will cause the GridView
measure its kid's layout by calling obtainView()
to first kid and then cause 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);
...
So, my question is: why mParent.isLayoutRequested()
return false
if I am using [loader mode]? or is it just a normal case ?
GridView
is similar toListView
so check out this great talk youtube.com/watch?v=wDBM6wVEO70. Unless you are getting some crash or memory low error, don't worry about it and let it call your methods. And yes in [loader mode] android will refresh GUI later whenever onLoadFinish() is called. – Saviour