我正在研究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存储在存储上是一个好主意(性能?)? 如果是的话,我怎么能在应用程序趋于内存不足时才这样做?
或者你对我的问题有一个完全不同的想法?
感谢您的帮助!
答案 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.Path和android.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);
}