2014-09-12 2 views
0

Я знаю, что эта тема обсуждалась так много раз, и я прочитал так много статей по обработке большого растрового изображения, но если мы отложим эту проблему в сторону, я хотел бы знать, почему одно растровое изображение принимает столько памяти. Теперь я разрабатываю приложение для Android с динамическим фоном. Фон представляет собой изображение в виде градиента, и оно должно идти от белого, от серого до черного. У меня есть 4 фоновых изображения, которые вместе создают желаемый градиент. Теперь, если я использую только одно изображение и сделаю фоновый статический, все отлично работает на устройстве с кучей VM объемом 64 Мб. Если, однако, я решил использовать все фоны, я получаю ошибку outofmemory даже на устройстве с кучей VM 128 Мб. Теперь, конечно, я могу понять, почему это происходит, если я загружаю все 4 изображения, но я отредактировал свой код, чтобы в одно мгновение загрузилось только 2 изображения (если одно фоновое изображение больше не отображается на экране, оно перерабатывается), и это работает, но едва. Если я добавляю только одно другое изображение, которое имеет незначительные размеры по сравнению с фоновым изображением, оно получает ту же ошибку.Одиночный битмап с огромным объемом памяти

Другая проблема во всем этом заключается в том, что я должен масштабировать растровые изображения после их загрузки. Я масштабирую их до размера экрана. Я знаю, что масштабирование занимает много памяти, но если я делаю вычисления, растровое изображение размером 1280x720, хранящееся как ARGB888, должно использовать не более 4 МБ памяти.

Установка largeHeap истина не будет делать какой-либо помощи или, как некоторые устройства имеют кучу, как низко как 16 МБ ..

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

Кроме того, загрузка пробы изображение не будет делать какой-либо помощи, так как изображения не очень большой (1000x1000 для xxhdpi плотности)

Код для BitmapDrawing:

private void DrawBackground(Canvas canvas) { 
    //temp and bgs[1] are loaded at start up, as they are required right away 
     if (bg_num > 3) { 
     canvas.drawBitmap(bgs[3], 0, 0, null); 

     if (!bgs[0].isRecycled()) 
     bgs[0].recycle(); 
     return; 
     } 

     if (bgs[0] == null) { 
     bgs[0] = Bitmap.createScaledBitmap(temp, getWidth(), getHeight(), 
     false); 
     temp.recycle(); 
     bgs_resized[0] = true; 
     } 

     if (bg_num == 2 && !bgs[0].isRecycled()) { 
     bgs[0].recycle(); 

     bgs[2] = BitmapFactory.decodeResource(getResources(), 
     R.drawable.bg3, bitmapOptions); 
     } 

     if (bg_num == 3 && !bgs[1].isRecycled()) { 
     bgs[1].recycle(); 
     bgs[3] = BitmapFactory.decodeResource(getResources(), 
     R.drawable.bg4, bitmapOptions); 
     } 

     if (!bgs_resized[bg_num]) { 

     temp = bgs[bg_num]; 
     bgs[bg_num] = Bitmap.createScaledBitmap(temp, getWidth(), 
     getHeight(), false); 
     bgs_resized[bg_num] = true; 
     temp.recycle(); 
     } 

     if (bg_pos < getHeight()) { 
     canvas.drawBitmap(bgs[bg_num], 0, (bg_pos += BG_TRANSITION_SPEED) 
     - getHeight() + 2, null); 
     canvas.drawBitmap(bgs[bg_num - 1], 0, bg_pos, null); 

     } else { 
     canvas.drawBitmap(bgs[bg_num], 0, 0, null); 
     ++bg_num; 

     bg_pos = 0; 

     } 

    } 

Я делаю что-то неправильно или мне нужно обратиться к NDK для моего решения.

Спасибо.

+3

Возможно, вы, скорее всего, что-то не так. Покажите нам свой код и, возможно, кто-то может помочь. – Okas

+0

Почему мой вопрос отмечен как не по теме. Все это приложение рисует фон. И проблема четко заявлена ​​... – Transcendental

ответ

0

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

1) используйте растровый завод, который декодирует ваше растровое изображение до необходимого размера. например, если для просмотра изображений требуется только 512x384, вы не хотите загружать растровое изображение большего размера в память.

вы можете сделать это следующим образом:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, 
     int reqWidth, int reqHeight) { 

    // First decode with inJustDecodeBounds=true to check dimensions 
    final BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeResource(res, resId, options); 

    // Calculate inSampleSize 
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 

    // Decode bitmap with inSampleSize set 
    options.inJustDecodeBounds = false; 
    return BitmapFactory.decodeResource(res, resId, options); 
} 

2) убедитесь, что при загрузке растрового изображения с диска, что вы делаете это в другом потоке затем пользовательский интерфейс.

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

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

Set<SoftReference<Bitmap>> mReusableBitmaps; 
private LruCache<String, BitmapDrawable> mMemoryCache; 

// If you're running on Honeycomb or newer, create a 
// synchronized HashSet of references to reusable bitmaps. 
if (Utils.hasHoneycomb()) { 
    mReusableBitmaps = 
      Collections.synchronizedSet(new HashSet<SoftReference<Bitmap>>()); 
} 

mMemoryCache = new LruCache<String, BitmapDrawable>(mCacheParams.memCacheSize) { 

    // Notify the removed entry that is no longer being cached. 
    @Override 
    protected void entryRemoved(boolean evicted, String key, 
      BitmapDrawable oldValue, BitmapDrawable newValue) { 
     if (RecyclingBitmapDrawable.class.isInstance(oldValue)) { 
      // The removed entry is a recycling drawable, so notify it 
      // that it has been removed from the memory cache. 
      ((RecyclingBitmapDrawable) oldValue).setIsCached(false); 
     } else { 
      // The removed entry is a standard BitmapDrawable. 
      if (Utils.hasHoneycomb()) { 
       // We're running on Honeycomb or later, so add the bitmap 
       // to a SoftReference set for possible use with inBitmap later. 
       mReusableBitmaps.add 
         (new SoftReference<Bitmap>(oldValue.getBitmap())); 
      } 
     } 
    } 
.... 
} 
Смежные вопросы