gpt4 book ai didi

android - 在 gridview 适配器中,getView(position == 0) 在加载器中的 setImageBitmap() 被调用太多次以测量布局

转载 作者:IT老高 更新时间:2023-10-28 22:22:52 24 4
gpt4 key购买 nike

我有一个 GridView 用于显示一些图标。

在我阅读本文之前 Displaying Bitmaps Efficiently从 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)
...

然后我尝试将代码更改为文章 Displaying Bitmaps Efficiently 中提到的 [Loader Mode] ,如下:

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) 在加载器的 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()返回falsemParent.requestLayout(); 将导致 GridView 通过调用 obtainView() 来测量其 child 的布局第一个 child ,然后导致 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?还是只是正常情况?

最佳答案

isLayoutRequested只是为了告诉您此 View 的布局是否已挂起.也就是说,在 requestLayout 之后被称为,isLayoutRequested将返回 true 直到下一个布局传递完成。 checkin requestLayout 的唯一原因是为了避免重复调用requestLayout如果无论如何都要进行布局,则在父级上。 isLayoutRequested这里是一个红鲱鱼:这不是 onMeasure 的原因被反复调用。

根本问题是ImageView每当您更改其可绘制对象时都会请求新布局。这是必要的,原因有两个:-

  1. ImageView 的大小可能取决于可绘制对象的大小,如果 adjustViewBounds已设置。这可能反过来影响其他 View 的大小,具体取决于布局:ImageView本身没有足够的信息知道。
  2. ImageView.onMeasure负责计算需要调整多少可绘制对象以适应 ImageView的边界,根据比例模式。如果新的drawable与旧drawable的大小不同,ImageView 必须再次测量以重新计算所需的缩放比例。

您只能通过保留 Bitmap 的本地缓存来解决加载程序过多的问题。 s 由装载机返回。缓存可能包含所有 Bitmap s 如果您知道没有那么多,或者只是 n 最近使用的。在您的 getView ,首先检查 Bitmap如果该项目存在于缓存中,则返回 ImageView已经设置为 Bitmap .只有不在缓存中时才需要使用加载器。

注意:如果底层数据可以更改,您现在需要确保在调用 invalidate 的同时使缓存无效在 GridView或通过 ContentResolver 通知.我在我的应用程序中使用了一些自制代码来实现这一点,它对我来说效果很好,但是 Square 的好人有一个名为 Picasso 的开源库如果您愿意,可以为您完成所有艰苦的工作。

关于android - 在 gridview 适配器中,getView(position == 0) 在加载器中的 setImageBitmap() 被调用太多次以测量布局,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12561295/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com