我有一个GridView
用于显示一些图标的。
在我从 Android 开发人员网站上阅读此高效显示位图之前,我直接在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)
...
然后我尝试将代码更改为有效显示位图一文中提到的[加载器模式] ,如下所示:
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);
在 Loader 的监听器中:
@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)
重复调用 g。
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()
. 我检查了源代码,发现它们最初是由imageView.setImageBitmap(result)
loader 的 onLoadComplete
方法调用的,并且在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 的方法,总是在 View.class 中的 [Direct Mode] 或 [Loader Mode] 中执行:
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();
会GridView
通过调用来测量其孩子的布局obtainView()
给第一个孩子,然后导致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);
...
所以,我的问题是:如果我使用 [loader mode]为什么要mParent.isLayoutRequested()
返回?false
还是只是正常情况?