ViewFlipper: OutOfMemoryError: размер растрового изображения превышает бюджет виртуальной машины - PullRequest
3 голосов
/ 22 ноября 2011

Я использую ViewFlipper в моем приложении для Android. После вызова startflipping (), если я позволю приложению работать в течение нескольких минут, я скоро получаю ошибку:

11-22 15:36:34.354: ERROR/dalvikvm-heap(428): 307200-byte external allocation too large for this process.
11-22 15:36:34.372: ERROR/(428): VM won't let us allocate 307200 bytes
11-22 15:36:34.375: ERROR/AndroidRuntime(428): Uncaught handler: thread main exiting due to uncaught exception
11-22 15:36:34.384: ERROR/AndroidRuntime(428): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
11-22 15:36:34.384: ERROR/AndroidRuntime(428):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
11-22 15:36:34.384: ERROR/AndroidRuntime(428):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459)
11-22 15:36:34.384: ERROR/AndroidRuntime(428):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:271)
11-22 15:36:34.384: ERROR/AndroidRuntime(428):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:296)
11-22 15:36:34.384: ERROR/AndroidRuntime(428):     at com.PlayerOrange.ViewPlaylist.populate(ViewPlaylist.java:115)
11-22 15:36:34.384: ERROR/AndroidRuntime(428):     at com.PlayerOrange.ViewPlaylist.access$0(ViewPlaylist.java:100)
11-22 15:36:34.384: ERROR/AndroidRuntime(428):     at com.PlayerOrange.ViewPlaylist$ProgressTask$1$1.run(ViewPlaylist.java:383)

Каждые 30 секунд я получаю информацию о памяти, например:

ActivityManager activityManager = (ActivityManager) getBaseContext().getSystemService(ACTIVITY_SERVICE);
                android.app.ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
                activityManager.getMemoryInfo(memoryInfo);

                Log.i(TAG, " memoryInfo.availMem " + memoryInfo.availMem + "\n" );
                Log.i(TAG, " memoryInfo.lowMemory " + memoryInfo.lowMemory + "\n" );
                Log.i(TAG, " memoryInfo.threshold " + memoryInfo.threshold + "\n" );

Что странно, так это то, что до того, как я получу Force Close (для outofmemoryError), я имею в DDMS это:

11-22 15:36:10.255: INFO/(428):  memoryInfo.availMem 50470912
11-22 15:36:10.255: INFO/(428):  memoryInfo.lowMemory false
11-22 15:36:10.264: INFO/(428):  memoryInfo.threshold 16777216

Понятия не имею, как решить эту ошибку.

Вот мой код для заполнения ViewFlipper:

private void populate() {
        for (int i = 0; i < jArray.length(); i++) {
            System.out.println("lungime" + jArray.length());
            LinearLayout l = new LinearLayout(this);
            l.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
                    LayoutParams.FILL_PARENT));
            l.setBackgroundColor(0x000000);
            l.setOrientation(LinearLayout.VERTICAL);
            vf.addView(l);

            File f = new File(Environment.getExternalStorageDirectory()
                    + "/Downloads/");

            File[] files = f.listFiles();

            Bitmap bitmap = BitmapFactory.decodeFile(files[i].getPath());
            img = new ImageView(this);
            img.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
                    LayoutParams.FILL_PARENT));

            img.setImageBitmap(bitmap);

            System.out.println("target " + target[i]);
            img.setOnTouchListener(this);
            img.setId(i);

            l.addView(img);
            img = null;

        }

vf = (ViewFlipper) findViewById(R.id.details);
            vf.setFlipInterval(Integer.valueOf(timer) * 1000);
            vf.startFlipping();
            populate();

Я получаю изображения из Интернета и сохраняю их на SDCard. После этого я получаю их из папки SDcard и добавляю их в viewFlipper.

Любая идея приветствуется. Заранее спасибо.

Ответы [ 3 ]

1 голос
/ 23 ноября 2011

Вы просто используете слишком много и слишком большие растровые изображения.

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

Как уже говорилось в другом ответе, вы можете сделать две разные вещи: уменьшить размер изображений или уменьшить количество изображений в памяти сразу.

Вы можете использовать кэширование или слабые ссылки, выможет уменьшить растровые изображения на лету.Это сравнительно продвинутые методы.Лучше всего, если возможно, просто использовать гораздо меньшие растровые изображения в качестве источника.

Если вы не можете, вот простое решение:

        img.setImageBitmap(bitmap);
        bitmap.recycle();
        System.out.println("target " + target[i]);

Это должно быть более быстро очищеновверх растрового объекта.Для получения дополнительной информации см. Следующее: recycle .

1 голос
/ 22 ноября 2011
  1. Используйте некоторый механизм кэширования, чтобы уменьшить использование памяти.
  2. Уменьшите изображения с помощью BitmapFactory.Options http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html

Кэширование здесь означает использование некоторой структуры данных, которая может сохранять эффективные ссылки на ваши изображения. Это просто означает, что вы можете получать доступ к изображениям по мере необходимости, через ваш кеш, и кеш будет пытаться сохранить только ссылки на изображения, которые необходимы, как требуется. Обычно это делается с помощью SoftReference: http://download.oracle.com/javase/6/docs/api/java/lang/ref/SoftReference.html или даже WeakReference: http://download.oracle.com/javase/6/docs/api/java/lang/ref/WeakReference.html

Вот пример: https://github.com/thest1/LazyList

0 голосов
/ 23 ноября 2011

В связи с тем, что ниже уже опрошено и получено ответ от экспертов.

OutOfMemoryError: размер растрового изображения превышает бюджет виртуальной машины

проверить по ссылке:

Странно нехватка памяти при загрузке изображения в растровый объект

...