首先是重要的代码行:
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), getDrawableForLvl(drawable));
int []pixels = new int[bitmap.getWidth()*bitmap.getHeight()];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
//..
pixels = null; // please gc remove this huge data
System.gc();
所以我正在开发一个具有多个级别的Android应用程序(游戏)。每个级别都是我在级别开始时作为位图加载的图像。然后我必须分析每个像素(第3行)。为此我创建了一个数组(第2行)。图像为1280x800,因此阵列的大小超过一百万英寸。这里没有问题,因为它是一个局部变量,它应该在方法返回时被销毁。但它是java,所以它不是-.-根据设备的不同,垃圾收集器的运行速度足够快。因此,当用户非常快地启动和关闭级别时,它会在第2行中生成java.lang.OutOfMemoryError。我猜是因为旧的数组尚未被删除,现在我有多个填充内存。
我可以使数组成为静态成员。所以它创建了一次并且始终可用。然后它不可能有多个实例。但我认为这是一种糟糕的编码风格,因为它在不需要时也可用(4 MB)。
我不需要同时使用所有像素。我将图像分成了一百多个矩形,所以我可以使用一个更小的数组,并用像素一个接一个地填充它。但我有理解方法参数can someone help me here的问题? 还有一种获取one pixel at position x,y的方法,但我想一百万个函数调用非常慢。
有人有更好的主意吗?在java中没有办法强制对象没有内存,是吗?
UPDATE1 : 由于vzoha建议只获得第一季度:
int []pixels = new int[bitmap.getWidth()/2*bitmap.getHeight()/2];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth()/2, bitmap.getHeight()/2);
给出一个ArrayIndexOutOfBound。我认为函数调用只是获取第一季度的像素,但仍然期望全尺寸数组和其他字段保持不变。
Update2 :我想我可以一行一行(第一季度半行半行):
int []pixels = new int[bitmap.getWidth()/2*bitmap.getHeight()/2];
for(int row = 0; row < bitmap.getHeight()/2; ++row)
bitmap.getPixels(pixels, bitmap.getWidth()/2, bitmap.getWidth(), 0, row, bitmap.getWidth()/2, 1);
但是当我为20x10的部分做到这一点时,它并不比单独获得每个像素好多少。好吧它好多了但是这个方法应该能够通过一次调用来做到这一点,不是吗?我只是没有得到这个“步幅”参数:“像素之间的条目数量[]要在行之间跳过(必须是&gt; =位图的宽度)。可以是负数。”当&gt; =宽度?
时,它怎么可能是负面的呢?答案 0 :(得分:1)
像素大小并不直接转化为图像在内存中占用的内存量。 Android中的位图(在使用ART之前)非常难以大量使用,同时避免了OOM异常({3}}。问题通常是实际上有足够的可用内存,但它已经变得支离破碎,并且没有单个连续块你需要的大小。
我的第一个建议(快速获胜)将是使用特定配置解码位图,您应该只能通过切换使用{{3}来占用之前使用的内存量的1/4 }。这将使用每像素1个字节而不是4个(默认为ARGB_8888)
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ALPHA_8
bitmap = BitmapFactory.decodeResource(getResources(), getDrawableForLvl(drawable), options);
我的下一个建议是扩展位图,然后将相应的位图放在hdpi,xhdpi,xxhdpi文件夹中。
答案 1 :(得分:0)
事实上,只获取特定区域的像素非常简单。 But the documentation is wrong about the stride parameter。它说:
public void getPixels(int [] pixels,int offset,int stride,int x,int y,int width,int height)
stride:行之间跳过的像素数量[]必须是&gt; =位图&#39; s宽度。可以是否定的。
但事实是它可以(并且在大多数情况下必须)小于位图的宽度,它只需要大于或等于传递的宽度(getPixels的倒数第二个参数),意思是我想要像素的区域的宽度。
所以要获取位图第一个四分之一的像素:
int []pixels = new int[bitmap.getWidth()>>1 * bitmap.getHeight()>>1]; // quarter of the bitmap size
bitmap.getPixels(pixels, 0, bitmap.getWidth()>>1, 0, 0, bitmap.getWidth()>>1, bitmap.getHeight()>>1);
或者获得具有x,y(左上角)和宽度,高度:
的特定矩形int []pixels = new int[width*height];
bitmap.getPixels(pixels, 0, width, x, y, width, height);
非常简单。这只是错误的文档,在我的大脑中扭曲。