【发布时间】:2012-09-24 08:24:10
【问题描述】:
我有一个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);
在 Loader 的监听器中:
@Override
public void onLoadComplete(Loader<Bitmap> arg0, Bitmap arg1) {
...
ImageView imageView = imageViewReference.get();
if (result != null && imageView != null) {
imageView.setImageBitmap(result);
}
}
基本上和训练代码一样,其实这种方式也可以。但是,我发现了一些不同的东西,在这种模式下,适配器中的getView() 方法被调用了太多次,但是,这些对该方法的重复调用总是使用“位置”参数== 0,这意味着某些东西会重复调用 getView(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() 中使用了加载器。我检查了源代码,发现它们最初是由 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);
...
所以,我的问题是:如果我使用[加载器模式],为什么mParent.isLayoutRequested() 会返回false?还是只是正常情况?
【问题讨论】:
-
据我所知正常,Android可以随时调用你适配器的任何方法,想调用多少次就调用多少次。它甚至因版本而异。永远不要假设任何事情。
GridView与ListView类似,因此请查看这篇精彩的演讲 youtube.com/watch?v=wDBM6wVEO70。除非您遇到崩溃或内存不足错误,否则不要担心,让它调用您的方法。是的,在 [加载器模式] 中,每当调用 onLoadFinish() 时,android 都会稍后刷新 GUI。 -
检查“设置>开发人员选项>显示布局更新”并启动您的应用程序。如果所有加载程序都完成后 GUI 已解决,那么您就可以开始了。
-
您找到解决方法了吗?我也明白了。
标签: android android-view android-gridview