Android-приложение сбой на Samsung Galaxy S3 (ошибка памяти)

У меня есть приложение для Android, которое снимает некоторые снимки, изменяет их размеры и отправляет их на внутренний сервер. Это приложение прекрасно работает на всех других телефонах (сэндвич с пряниками и мороженым), за исключением Samsung Galaxy S3. Всякий раз, когда он принимает снимки и пытается изменить размер, у него заканчивается память. Первоначально я думал, что это проблема с частью повторной калибровки, и я реализовал объект растрового изображения с помощью insamplesize и пробовал все, но он все еще продолжал сбой. Затем я понял, что когда приложение запускается сначала, оно использует много памяти. На HTC и всех других телефонах, когда мое приложение запускается, оно использует около 4 МБ, но на Galaxy S3 оно использует около 30 МГ - почти в 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. Мои вопросы:

  • Может ли кто-нибудь сказать мне, почему Galaxy S3 использует до 90% памяти, когда она загружает мое приложение вместо 60% на телефоны HTC.
  • Есть ли что-то неправильное в коде re-size, из-за которого у моего приложения заканчивается память.

Любая помощь будет принята с благодарностью, поскольку я уже потратил 3 дня на эту проблему: - (.

Ответы

Ответ 1

Я сам решил проблему. Приложению, не имеющему памяти, не нужно было ничего делать с указанным выше кодом. Я добавил MAT, и я увидел, что объекты растрового изображения сохраняются в живых из предыдущих представлений. Поэтому я удалил графику из представления и решил проблему с памятью.

Ответ 2

umm... Я знаю, что это старый вопрос, но вот что я думаю.

Galaxy S3 использует плотность xhdpi, поэтому выделяет больший размер кучи при запуске (насколько я знаю, 32 МБ)

но если у вас нет ресурсов xhdpi в каталоге res, то он будет вызывать любые изображения по умолчанию в drawable или из hdpi, который является самым близким к плотности xhdpi.

Затем он будет расширять изображение, чтобы соответствовать ему, и на этих этапах расширение изображения будет занимать много памяти (возможно), что приведет к проблемам с памятью.

Вы можете решить эту проблему, включив Режим совместимости экрана или вы можете просто создать (если не там по умолчанию) drawable-xhdpi, обеспечивая соответствующие ресурсы для устройств xhdpi, таких как Galaxy S3.

Ответ 3

Ого. В течение нескольких недель мы столкнулись с проблемой нехватки памяти на S3. Наконец, применил один из методов в этом потоке.

В нашем приложении у нас есть drawable-hdpi все изображения для приложения. На большинстве телефонов у нас не было проблем. На S3 приложение будет потреблять в 2 раза больше памяти, а затем выйдет из памяти.

Я только что создал папку drawable-xhdpi с тем же содержимым, что и папка drawable-hdpi, и запустила ее на S3. Сразу же заметили, что объем памяти равен 1/2, и проблем с памятью нет.

Это был разочаровывающий опыт. Надеюсь, другие люди знают, как искать эту тему и экономить время на отладку.

спасибо

Ответ 4

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 (что раздражало). Но приложение работает прямо сейчас! Thanx... user881148