我有一个Android应用程序可以拍摄一些照片,重新调整大小并将它们发送到后端服务器。除三星Galaxy S3外,这个应用程序在所有其他手机(姜饼和冰淇淋三明治)上完美运行。每当它拍摄图片并尝试重新调整大小时,它就会耗尽内存。最初我认为这是重新调整大小部分的一个问题,我使用insamplesize实现了位图对象并尝试了所有内容,但它仍然在崩溃。然后我意识到,当应用程序首先启动时,它会占用大量内存。在HTC和所有其他手机上,当我的应用程序启动时,它耗尽了大约4 MB,但在Galaxy S3上,它耗尽了大约30 MG - 几乎是10倍。我似乎无法弄清楚是什么会导致它消耗更多的内存。我正在回收所有对象和布局(我认为)。这是我必须调整图像大小的代码:
public static void resizeImage(String pathOfInputImage,
String pathOfOutputImage) {
try {
int inWidth = 0;
int inHeight = 0;
float factor;
InputStream in = new FileInputStream(pathOfInputImage);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, options);
inWidth = options.outWidth;
inHeight = options.outHeight;
in.close();
in = null;
options = null;
if (inWidth > inHeight) {
factor = (float) inHeight / 480;
} else {
factor = (float) inWidth / 480;
}
options = new BitmapFactory.Options();
Bitmap roughBitmap;
if(Build.VERSION.SDK_INT < 12) {
System.gc();
}
try
{
in = new FileInputStream(pathOfInputImage);
options.inSampleSize = 4;
roughBitmap = BitmapFactory.decodeStream(in, null, options);
}
catch (OutOfMemoryError e)
{
roughBitmap = Utils.fetchRoughBitmap(pathOfInputImage, factor);
}
finally
{
roughBitmap = Utils.fetchRoughBitmap(pathOfInputImage, factor);
}
in.close();
in = null;
boolean rotate = false;
Bitmap rotatedBitmap = null;
if (isNeedToRotate(pathOfInputImage)) {
rotate = true;
Matrix m = new Matrix();
m.postRotate(90);
try
{
rotatedBitmap = Bitmap.createBitmap(roughBitmap, 0, 0,
roughBitmap.getWidth(), roughBitmap.getHeight(), m,
true);
}
catch (OutOfMemoryError e)
{
rotatedBitmap = Bitmap.createBitmap(roughBitmap, 0, 0,
roughBitmap.getWidth()/2, roughBitmap.getHeight()/2, m,
true);
}
}
if (rotate) {
Utils.log(TAG, "Rotate Invoked :------->");
int temp = inHeight;
inHeight = inWidth;
inWidth = temp;
}
options.inSampleSize = Math.round(factor);
float dstWidth = (int) inWidth / factor;
float dstHeight = (int) inHeight / factor;
Bitmap resizedBitmap;
if (rotate) {
try
{
resizedBitmap = Bitmap.createScaledBitmap(rotatedBitmap,
(int) dstWidth, (int) dstHeight, true);
}
catch (OutOfMemoryError e)
{
resizedBitmap = Bitmap.createScaledBitmap(rotatedBitmap,
(int) dstWidth/2, (int) dstHeight/2, true);
}
} else {
try
{
resizedBitmap = Bitmap.createScaledBitmap(roughBitmap,
(int) dstWidth, (int) dstHeight, true);
}
catch (OutOfMemoryError e)
{
resizedBitmap = Bitmap.createScaledBitmap(roughBitmap,
(int) dstWidth/2, (int) dstHeight/2, true);
}
}
try
{
FileOutputStream out = new FileOutputStream(pathOfOutputImage);
resizedBitmap.compress(Bitmap.CompressFormat.PNG, 80, out);
}
catch (Exception e) {
Utils.log("Image", e.getMessage() + e);
}
//Free up the memory.
roughBitmap.recycle();
resizedBitmap.recycle();
if (rotatedBitmap != null) {
rotatedBitmap.recycle();
}
} catch (IOException e) {
Utils.log("Image", e.getMessage() + e);
}
}
private static Bitmap fetchRoughBitmap(String pathOfInputImage, float factor)
{
Bitmap roughBitmap = null;
try
{
FileInputStream in = new FileInputStream(pathOfInputImage);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = Math.round(factor);
roughBitmap = BitmapFactory.decodeStream(in, null, options);
return roughBitmap;
}
catch (OutOfMemoryError mem_error)
{
return Utils.fetchRoughBitmap(pathOfInputImage, factor+1);
}
catch (FileNotFoundException e)
{
//return Utils.fetchRoughBitmap(pathOfInputImage, factor+1);
return roughBitmap;
}
}
这段代码工作正常,因为我通过一个递归循环运行它,直到它没有内存耗尽,但我的结果图像只有大约300x300像素,我需要它至少640x480。我的问题是:
任何帮助将不胜感激,因为我已经在这个问题上花了3天时间: - (。
答案 0 :(得分:9)
Galaxy S3使用xhdpi密度,因此在启动时分配更大的堆大小(据我所知,32mb)
但如果您的res目录中没有任何xhdpi资源,那么它将调用drawable中的任何默认图像或最接近xhdpi密度的hdpi。
然后它将扩展图像以适应它的需要,并且在此阶段扩展图像将占用大量内存,(可能)导致内存不足问题。
您可以通过启用 Screen Compatibility Mode 解决此问题,也可以创建(如果不是默认情况下)drawable-xhdpi,提供 Appropriate Resources 适用于像Galaxy S3这样的xhdpi设备。
答案 1 :(得分:7)
哇。几周以来,我们一直在努力解决S3上的内存不足问题。最后,应用了这个线程中的一种技术。
在我们的应用程序中,我们有drawable-hdpi拥有应用程序的所有图像。在大多数手机上,我们都没有问题。在S3上,应用程序将占用2倍的内存,然后遇到内存不足的问题。
我刚创建了drawable-xhdpi文件夹,其内容与drawable-hdpi文件夹相同,并在S3上运行。立即注意到内存占用量为1/2并且没有内存不足问题。
这是一次令人沮丧的经历。希望其他人知道寻找这个线程并节省数小时的脱气。
感谢
答案 2 :(得分:5)
我自己解决了这个问题。内存耗尽的应用程序无需对上述代码执行任何操作。我添加了MAT,我看到位图对象从以前的视图中保持活着状态。所以我从视图中删除了图形,它解决了内存问题。
答案 3 :(得分:0)
I overwrote the onDestroy method and added the following line: layout.setBackgroundDrawable(null);. Please let me know if this worked or didn't work for you.
- user881148
很酷,它对我有用......在布局上加了一点背景图片。我没有使用BitmapDrawables或Bitmap,而是在从位图转换后使用Drawables。
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.outerspace);
Drawable bitDraw = new BitmapDrawable(getResources(), bitmap);
main.setBackgroundDrawable(bitDraw);
我的问题是,所有设备都在期待S3(这很烦人)。但该应用程序现已启动并运行!感谢名单... user881148