Android应用程序在三星Galaxy S3上崩溃(内存不足错误)

时间:2012-08-10 20:41:34

标签: android

我有一个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。我的问题是:

  1. 任何人都可以告诉我为什么Galaxy S3在第一次加载我的应用程序时会消耗高达90%的内存而不是HTC手机上的60%。
  2. 在重新调整大小的代码中是否有任何错误导致我的应用程序内存不足。
  3. 任何帮助将不胜感激,因为我已经在这个问题上花了3天时间: - (。

4 个答案:

答案 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