1

这是我的代码:

int[] image = {R.drawable.image1, R.drawable.image2, R.drawable.image1, R.drawable.image2,
        R.drawable.image1, R.drawable.image2, R.drawable.image1, R.drawable.image2,
        R.drawable.image1, R.drawable.image2, R.drawable.image1, R.drawable.image2,
        R.drawable.image1, R.drawable.image2, R.drawable.image1, R.drawable.image2,
        R.drawable.image1, R.drawable.image2, R.drawable.image1, R.drawable.image2,
        R.drawable.image1, R.drawable.image2, R.drawable.image1, R.drawable.image2};

和getView:

@Override
    public View getView(int position, View convertView, ViewGroup parent) {

        convertView=LayoutInflater.from(getApplicationContext()).inflate(R.layout.item, null);
        ImageView imageView = (ImageView) convertView.findViewById(R.id.imageView);
        imageView.setBackgroundResource(image[position]);

        return convertView;
    }

一切都很好。没有OOM。

然后,我想先对可绘制对象进行采样:

public static Bitmap sampleImage(Context context, int resourceId, int sampleSize) {        
            Bitmap resizeBmp = null;
            BitmapFactory.Options opts = new BitmapFactory.Options();
            opts.inSampleSize = sampleSize;
            resizeBmp = BitmapFactory.decodeResource(context.getResources(), resourceId, opts);

            return resizeBmp;
        }

和新的getView:

@Override
    public View getView(int position, View convertView, ViewGroup parent) {

        convertView=LayoutInflater.from(getApplicationContext()).inflate(R.layout.item, null);
        ImageView imageView = (ImageView) convertView.findViewById(R.id.imageView);
        Bitmap item = BitmapUtil.sampleMaskInShelf(getApplicationContext(), image[position], 4);
        imageView.setImageBitmap(item);
        //      imageView.setBackgroundResource(image[position]);

        return convertView;
    }  

事情发生了。起初,应用程序不会崩溃。但是使用的内存超过50MB,上下滚动后,导致OOM。

问题是:1)为什么对图像进行采样会增加使用的内存。2)如何减少使用的内存,还有其他方法吗?

4

4 回答 4

5

It seems like you are working with a ListView here?

In that case, you would be better served (and hopefully conserving a significant amount of memory) with a couple of steps:

  1. You want to try to re-use the convertView whenever possible. Many articles have been written on how to do this. Here is one.
  2. It looks like you only really have two different images (image1 and image2). It also seems like you are sampling the bitmap every time getView() is called. You probably ought to pre-calculate the two sampled bitmaps, and just use those over and over again.
于 2012-09-26T01:42:44.213 回答
2

有三篇优秀的 Android 培训文章涵盖了这个确切的问题:

  1. 有效加载大型位图
  2. 缓存位图
  3. 显示位图(特别是使用 GridView)

我可能会尝试阅读所有这三个,了解他们使用的技术并下载将所有培训代码封装到一个示例中的示例应用程序。我认为在您的情况下,将图像预采样到它们的显示尺寸然后使用LruCache可能就足够了。

于 2012-09-30T20:31:07.293 回答
0

您应该尝试重用视图,而不是每次都创建新视图,例如..

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if(v == null)  {   
        v=LayoutInflater.from(getApplicationContext()).inflate(R.layout.item, null);
    } 
    ImageView imageView = (ImageView) convertView.findViewById(R.id.imageView);
    imageView.setBackgroundResource(image[position]);

    return v;
}

对于 OOM 的更多操作,您应该查看以下链接.. http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

或者你可以使用 UniversalImage Loader Library 来加载图像。你可以从 UniversalImageLoader找到它的库

希望这有帮助...

于 2012-10-04T12:41:32.137 回答
0

垃圾收集器不会自动为您处理位图解除分配,因此任何时候您将位图直接分配给变量时,您还需要在完成后调用 bitmap.recycle()。不这样做会导致内存泄漏,这就是你所拥有的。但是,如果将位图分配给可绘制对象,然后调用 bitmap.recycle(),然后尝试使用可绘制对象,则会出现异常,因为可绘制对象无法访问回收的位图。

我正在编写一个类似于您所拥有的 ListView,而我最终做的是在当前视口上方十多个插槽的任何位图上调用 bitmap.recycle,在该 ListView 项目上设置一个标志以显示其位图被回收,然后让 getView 在用户向上滚动时重新加载位图。

于 2012-10-02T17:32:10.157 回答