Android - GC在使用“较大”图片时导致ListView滚动卡顿

3
在列表视图中,我想在列表项上绘制一张图片。 这20张图片需要按垂直模式缩放以填充宽度。 手机分辨率为480 x 800像素(SGS2)。 图像分辨率为400 x 400,大小约为100KB。 我将这些图像放在drawable文件夹中。
当我滚动列表时,它并不流畅。
我了解一些事情: - 应用程序堆大小=有限的,首次运行时分配=13MB,余下1MB。 - 我有GC_FOR_ALLOC日志消息,这会使系统停顿15毫秒。(这是我认为导致滚动卡顿的原因)。 - 更改代码后,我还看到GC_CONCURRENT消息。
通过这些GC消息,我了解到每次滚动到另一个新的列表视图条目中的图像时,垃圾回收都会启动。 到目前为止,我可以分析出这一点,但我不知道该如何修复和永久删除GC。 我已经将图像缩小到100 x 100,并且这样可以延迟GC消息更长时间。 但最终GC仍然会启动。 我确实使用convertview回收视图,并且已经在视图内使用了holder。
我了解了重用图像内存,但不确定是否以及如何执行此操作。 或者,当在列表视图中使用这些较大的图像时,这可能是“正常”的情况,我需要重新思考图像的绘制,并且只有在滚动结束时才开始绘制?
我应该使用ListView来滚动浏览图片吗?
2012-12-31_02:11 我已经实现了setOnScrollListener,这使滚动平滑了。 我认为这是我必须进一步调查的代码片段。
列表视图适配器
public class ListviewAdapter extends BaseAdapter {

    private static Activity activity;
    private int[] data;
    private static LayoutInflater mInflater = null;

    public ListviewAdapter(Activity a, int[] d) {
        activity = a;
        data = d;
        mInflater = (LayoutInflater) activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public int getCount() {
        return data.length;
    }

    public Object getItem(int position) {
        return position;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.listviewitem, parent,
                    false);
            holder = new ViewHolder();

            holder.picture = (ImageView) convertView.findViewById(R.id.image);
            convertView.setTag(holder);

        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        if (!MainActivity.isScrolling) {
    holder.picture.setImageResource(data[position]);
    }

        return convertView;
    }

    static class ViewHolder {
        ImageView picture;
    }

}

列表视图 XML

<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content">
  <ImageView
      android:id="@+id/image"
      android:src="@drawable/stub"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:contentDescription="Animal images"
        android:scaleType="fitCenter"
        android:scrollingCache="false"
        android:animationCache="false" 
        />

</LinearLayout>
2个回答

2
您一直在打开位图,这些占用了相当多的内存,需要回收以便为您将要加载的大量位图腾出空间。您可以通过使用BitmapFactory选项来缩小加载图像的大小(如果不会以全尺寸显示),这样,您只需要占用足够填充视图的内存,从而减少GC调用。您还可以尝试在适配器内部保持某种缓存,以避免每次重新加载位图。

谢谢您指导我这个方向。 我将尝试解决它并尽快给出反馈。我已经尝试将图像保持在我的显示分辨率以下。 图像= 400x400,显示= 480 x 800,但我仍然会找出当调整图像大小时会发生什么内存优化。 - Gaston
我使用了BitmapFactory之后发现,图片的大小调整不是问题所在。因此我会继续检查缓存可能性和“回收”(不确定我是否已经这样做了)。 - Gaston

0

我以为使用ViewHolders可以回收视图。或者是inflater解决了这个问题? 我正在阅读有关图像的懒加载,但我认为这会给我一个非常懒惰的解决方案,我不会学到太多东西。 现在我正在调试并学习一些小技巧,其他人也可以阅读和再次学习。如果我错了,请纠正我。 - Gaston
我认为你提到的OnScrollListener是我需要的部分。由于这些图片都很“大”(400x400像素),我想我总是会触发GC。 - Gaston
经过阅读和实验,我明白了并不存在适用于所有人的工具。通过尝试不同的代码片段,延迟加载是一个很好的起点。 - Gaston

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接