Android Out Of Memory异常存储大量字节

时间:2016-02-22 20:43:55

标签: java android out-of-memory bytearray

我正在研究android中的绘画应用程序。 目前我正在处理撤销功能 - 我的想法是存储更改的像素的坐标和颜色。

我正在使用RGB来解决性能问题 - 所以它们存储在一个字节数组中。

currentRGBPixelArray是包含旧ARGB值的数组。 updatedRGBPixelArray是包含新ARGB值的数组。

如果总是3个字段中的值不同,我知道我必须存储这些值。这是在Integer,Byte []对上完成的,其中Integer是RGBPixelArray中像素的索引。

但是使用这段代码时,我会在存储大量数据时出现内存异常(例如,如果背景或像1920 * 1080这样的大屏幕区域被更改,可能会多次)。

这是我的代码:

List<Pair<Integer, Byte[]>> changeTupelHolder = new ArrayList<>();
for (int index = 0; index < width; index += 4) 
{
     if (currentRGBPixelArray[index] != updatedRGBPixelArray[index] ||
         currentRGBPixelArray[index+1] != updatedRGBPixelArray[index+1] ||
         currentRGBPixelArray[index+2] != updatedRGBPixelArray[index+2]) 
     {
           Pair<Integer, Byte[]> changeTupel = 
               new Pair<>(index, 
                          new Byte[]{currentRGBPixelArray[index],
                                     currentRGBPixelArray[index+1],
                                     currentRGBPixelArray[index+2]});
           changeTupelHolder.add(changeTupel);
     }
}

然后,在调用撤消时,changeTupelHolder再次存储在堆栈中并进行伪装。

如何处理内存不足异常? 将changeTupelHolder存储在存储上是一个好主意(性能?)? 如果是的话,我怎么能在应用程序趋于内存不足时才这样做?

或者你对我的问题有一个完全不同的想法?

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

这是保存图像数据的非常低效的方式。保存图像数据的正确方法是字节数组字节数据[] =新字节[4 * NUM_PIXELS]。获得像素的颜色将是数据[pixelnum * 4 + COLOR_INDEX],其中颜色索引对于α为0,对于红色为1,对于绿色为2,对于蓝色为3。

你正在做的事情 - 你创造了数以百万计的小对象,每个对象都有自己的大量开销,每个对象都要存储一个字节。这会杀死一台PC。移动电话使用分配可怕,高性能Android代码的关键是最小化分配的对象数量。

我知道现代的思想流派不会想到表现,直到你知道这是一个问题,但那里有一个巨大的星号 - 你仍然需要运用常识。常识应该告诉你每个像素1个对象是一个坏主意。

答案 1 :(得分:0)

我会用矢量做这个。

实际上我已经用向量做了一些类似于undo / redo的事情,并且从未遇到过Out of Memory Exception。

我使用android.graphics.Pathandroid.graphics.Paint创建了一个矢量对象。

以下是将SVG转换为路径并绘制的示例代码:

public VectorPathObject(final List<List<Object>> actions, final float left, final float top, final String color, final float strokeWidth) {
    mPath = new Path();
    for (List<Object> action : actions) {
        switch (action.get(0).toString()) {
            case M:
                mPath.moveTo(left + Float.parseFloat(action.get(1).toString()), top + Float.parseFloat(action.get(2).toString()));
                break;
            case Q:
                mPath.quadTo(left + Float.parseFloat(action.get(1).toString()), top + Float.parseFloat(action.get(2).toString()), left + Float.parseFloat(action.get(3).toString()), top + Float.parseFloat(action.get(4).toString()));
                break;
            case L:
                mPath.lineTo(left + Float.parseFloat(action.get(1).toString()), top + Float.parseFloat(action.get(2).toString()));
                break;
        }
    }
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setStyle(this.paintStyle);
    mPaint.setStrokeCap(this.lineCap);
    mPaint.setStrokeJoin(Paint.Join.MITER);
    mPaint.setColor(Color.parseColor(color));
    mPaint.setStrokeWidth(strokeWidth);
    mPaint.setAlpha(this.opacity);
}