加载GridView位图时出现Android OutOfMemoryError

时间:2012-03-30 00:21:35

标签: android memory

我正在尝试将一些非常小的图片(平均大小为90kb)加载到Android中的gridview中。每当我加载超过9张图像时,我就会遇到内存问题。我已经尝试将图像缩放到更小的尺寸,尽管这在一定程度上起作用,但由于图像质量太差,它并不是真正的解决方案。

代码在

之下
private Context mContext;
private ArrayList<Bitmap> photos = new ArrayList<Bitmap>();
public Bitmap [] mThumbIds;

public ImageAdapter(Context c) {
    mContext = c;
}


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

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

public Bitmap scaleBitmap(String imagePath) {
    Bitmap resizedBitmap = null;
    try {
        int inWidth = 0;
        int inHeight = 0;

        InputStream in;

        in = new FileInputStream(imagePath);

        // decode image size (decode metadata only, not the whole image)
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(in, null, options);
        in.close();
        in = null;

        // save width and height
        inWidth = options.outWidth;
        inHeight = options.outHeight;

        // decode full image pre-resized
        in = new FileInputStream(imagePath);
        options = new BitmapFactory.Options();
        // calc rought re-size (this is no exact resize)
        options.inSampleSize = Math.max(inWidth/300, inHeight/300);
        // decode full image
        Bitmap roughBitmap = BitmapFactory.decodeStream(in, null, options);

        // calc exact destination size
        Matrix m = new Matrix();
        RectF inRect = new RectF(0, 0, roughBitmap.getWidth(), roughBitmap.getHeight());
        RectF outRect = new RectF(0, 0, 300, 300);
        m.setRectToRect(inRect, outRect, Matrix.ScaleToFit.CENTER);
        float[] values = new float[9];
        m.getValues(values);

        // resize bitmap
        resizedBitmap = Bitmap.createScaledBitmap(roughBitmap, (int) (roughBitmap.getWidth() * values[0]), (int) (roughBitmap.getHeight() * values[4]), true);

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return resizedBitmap;
}


public void populateGrid() {
    File sdDir = new File("mnt/sdcard/Pictures");
    File[] sdDirFiles = sdDir.listFiles();
    for(File singleFile : sdDirFiles) {
        String filePath = singleFile.getAbsolutePath();
        Bitmap bmp = scaleBitmap(filePath);
        photos.add(bmp);
    }
    mThumbIds = photos.toArray(new Bitmap[(photos.size())]);
}

// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
    ImageView imageView;
    if (convertView == null) {  // if it's not recycled, initialize some attributes
        imageView = new ImageView(mContext);
        imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setPadding(8, 8, 8, 8);
    } else {
        imageView = (ImageView) convertView;
    }
    imageView.setImageBitmap(mThumbIds[position]);
    return imageView;
}

@Override
public int getCount() {
    return mThumbIds.length;
}
}

2 个答案:

答案 0 :(得分:2)

两个考虑因素:

  1. 90kb压缩图像大小并不重要。内存使用取决于位图的实际分辨率 - 在这种情况下,300 * 300 * 4bpp,因此每位图大约360k。

  2. 姜饼有一些缺陷,因为Bitmap内存存储在本机数组(而不是Java堆)中,并且垃圾收集同时发生。由于这个事实,有时需要内存管理器更长时间才能意识到可以重用Bitmap内存。

  3. 因此,其结果是:

    1. 在估算内存使用量时,请考虑实际解压缩的位图大小。
    2. 尽可能地回收中间位图,以帮助更快地回收内存。例如,如果要缩放位图,请保存对预缩放源的引用,并在缩放完成后回收源(与缩放的结果进行比较,因为可能会返回相同的位图)。
    3. 如果可以,请在ICS设备上测试您的代码。然后,您可以使用堆检查工具来了解大多数内存的使用位置。正弦ICS在Java堆上分配位图内存,您将准确了解位图内存使用情况。

答案 1 :(得分:1)

位图使用大量内存,如果已将图像保存到内存中,最好只使用文件路径并将其推送到ImaveView上。

ImageView img = new ImageView(getApplicationContext());;

img.setImageBitmap(BitmapFactory.decodeFile(media.getThumbPath()));
img.setScaleType(ImageView.ScaleType.CENTER_INSIDE);

myLinearLayout.addView(img);

这样的事情可能会更好。这样您就不会将所有位图存储到堆中。