1

我有一个将图像从服务器加载到 ImageView 的列表视图。Listview 实现了 viewholder 模式,并有一个非常简单的行相对布局。对于延迟图像加载,我尝试了universalimageloader,picasso,目前正在使用基于google volley的glide,它应该非常快。但是:我的列表视图在用服务器图像替换占位符图像时仍然口吃,我不知道为什么,这是我的适配器代码:

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View rowView = convertView;
        News newsItem = getItem(position);

        if (rowView == null) {
            LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            rowView = inflater.inflate(mResource, null);
            // Create a viewHolder enabled row
            NewsViewHolder viewHolder = new NewsViewHolder();
            viewHolder.newsTitle = (TextView) rowView.findViewById(R.id.news_title);
            viewHolder.newsSubTitle = (TextView) rowView.findViewById(R.id.news_sub_title);
            viewHolder.newsDescription = (TextView) rowView.findViewById(R.id.news_desc);
            viewHolder.newsDate = (TextView) rowView.findViewById(R.id.news_date);
            viewHolder.newsThumb = (ImageView) rowView.findViewById(R.id.news_thumb);
            rowView.setTag(viewHolder);
        }
        NewsViewHolder holder = (NewsViewHolder) rowView.getTag();

        // Fill in fields of the current row of the NewsListView
        holder.newsTitle.setText(newsItem.title);
        holder.newsSubTitle.setText(newsItem.subTitle);
        holder.newsDescription.setText(newsItem.desciption);
        holder.newsDate.setText(SimpleDateFormat.getDateInstance().format(new Date(Long.parseLong(newsItem.date) * 1000)));

        Glide.load(newsItem.imageThumb)
                .centerCrop()
                .placeholder(R.drawable.placeholder)
                .into(holder.newsThumb);

        return rowView;
    }
}

/*
 * ViewHolder class for NewsListView
 */
public static class NewsViewHolder {
    public TextView newsTitle;
    public TextView newsSubTitle;
    public TextView newsDescription;
    public TextView newsDate;
    public ImageView newsThumb;
}

该列表仅在我第一次滚动时出现口吃,因此当我的图像被检索并通过滑行粘贴到列表中时。将图像粘贴到列表视图中后,滚动就像从一开始就应该的那样光滑。

我做错了什么?如何有效地找出导致挂断的原因?我不是 Traceview 的专家,它会产生大量数据进行筛选。

谢谢你的帮助!

4

3 回答 3

4

ImageView连续请求布局可能会导致卡顿。见ImageView.setImageDrawable

if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
    requestLayout();
}

我可以看到单个列表项非常复杂(5 需要花费大量时间来布置,特别是如果整个列表在每次图像加载时都布置好。

关键是大小R.drawable.placeholder。在第一次加载时.placeholder()总是显示,因为必须从 Glide 磁盘缓存中读取图像(即:后台 I/O)。来回滚动会填充内存缓存,这会导致立即加载(无后台线程),并且.placeholder()出于这个原因也没有显示 → 没有大小变化 → 没有requestLayout()

它还有助于你有ImageView一个固定大小(centerCrop()假设从池和您的回收行。此外,当现有行被回收时,其中已经显示了相同大小的图像,因此不会重新布局。BitmapBitmapBitmapViewHolderImageView

注意:Glide 不是基于 Volley 的,有可能使用 Volley via volley-integration,但默认情况下它不依赖它。虽然这个问题很老了,但也许你所说的在 3.0.0 之前是正确的。

于 2015-07-06T12:39:07.733 回答
1

看看你的日志猫。也许,您遇到的卡顿是由于垃圾收集器 (GC) 试图为新的位图重新分配堆(您应该看到GC_FOR_ALLOC日志)。如果是这样的话,那就没什么可做的了……ART 极大地改进了 GC 的工作方式(在 ART 上尝试一下)。

如果您的位图大小相同,则可以重用位图,以便运行时不必为新位图分配更多空间,如下所述:

https://developer.android.com/training/displaying-bitmaps/manage-memory.html#inBitmap

如果您使用 Glide,您可以预填充位图池以实现相同的目的。

于 2014-11-26T16:16:50.317 回答
0

尝试将您的代码更改为:

if (rowView == null) {
    LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    rowView = inflater.inflate(mResource, null);
    // Create a viewHolder enabled row
    NewsViewHolder viewHolder = new NewsViewHolder();
    viewHolder.newsTitle = (TextView) rowView.findViewById(R.id.news_title);
    viewHolder.newsSubTitle = (TextView) rowView.findViewById(R.id.news_sub_title);
    viewHolder.newsDescription = (TextView) rowView.findViewById(R.id.news_desc);
    viewHolder.newsDate = (TextView) rowView.findViewById(R.id.news_date);
    viewHolder.newsThumb = (ImageView) rowView.findViewById(R.id.news_thumb);
    rowView.setTag(viewHolder);
} else { // NEW
    NewsViewHolder holder = (NewsViewHolder) rowView.getTag();
}
于 2014-06-07T17:40:55.117 回答