2012-03-10 3 views
0

Я использую следующую функцию, чтобы получить фотографию контакта в Android, где ключ поиска данного лица дается:OutOfMemoryError при отображении фотографий контактов в Android (размер растрового изображения превышает бюджет VM)

public Bitmap getContactPhoto(String lookup_key) { 
    Uri lookUpUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookup_key); 
    Uri contentUri = ContactsContract.Contacts.lookupContact(ctx.getContentResolver(), lookUpUri); 
    InputStream stream = null; 
    try { 
     stream = ContactsContract.Contacts.openContactPhotoInputStream(ctx.getContentResolver(), contentUri); 
    } 
    catch (Exception e) { 
    } 
    if (stream != null) { 
     return BitmapFactory.decodeStream(stream, null, bitmapOptions); 
    } 
    else { 
     return null; 
    } 
} 

Когда я показываю эти контакты фотографии в списке, я иногда читаю следующее сообщение об ошибке в отчетах о сбоях в консоли разработчика:

Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget(Heap Size=6023KB, Allocated=3002KB, Bitmap Size=27152KB) 

Означает ли это, что мое приложение может использовать около 3 МБ кучи, но одно растрового изображения было примерно 27MB?

Я прочитал много вопросов здесь на переполнение стека относительно OutOfMemory ошибки, но это было в основном о:

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

Но как я могу предотвратить ошибку в моем случае? Поскольку я получаю только фотографии контактов, я не знаю, есть ли у меня огромные растровые изображения, которые нужно масштабировать. И утечка контекста, похоже, не имеет места здесь.

Это способ отображения изображения:

imageView.setVisibility(View.VISIBLE); 
imageView.setBackgroundResource(R.drawable.background); 
if (<BITMAP_OBJECT> != null) { 
    imageView.setImageBitmap(<BITMAP_OBJECT>); 
} 
else { 
    imageView.setImageBitmap(null); 
} 
+0

проблема не связана с тем, что вы показываете. Пожалуйста, прикрепите код, где getContactPhoto() называется – Blackbelt

+0

Извините, я добавил это сейчас. – caw

+0

Вы называете последний фрагмент, который вы отправили в каком-то адаптере. – Blackbelt

ответ

2

Когда вы настраиваете ваш Bitmap к ImageView, попробуйте сделать следующее:

Bitmap oldBitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap(); 
imageView.setImageDrawable(null); 
oldBitmap.recycle(); 
imageView.setImageBitmap(newBitmap); 

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

+0

Спасибо! Когда я попытался реализовать это, результат imageView.getDrawable() не имеет метода getBitmap(). Кроме того, это не ошибка в моем случае, когда одно растровое изображение было слишком большим? – caw

+0

Вы должны отдать его в битмап. Если вы устанавливаете 'Bitmap' для этих' ImageView', то это безопасный листинг. Кроме того, основная проблема может быть просто исчерпанной. Иногда эти ошибки обманчивы. Стоит кадр в любом случае, и это хорошая практика. –

+0

Спасибо, теперь это работает! К сожалению, я получаю следующее исключение во время выполнения: «Canvas: пытается использовать переработанное растровое изображение». Поэтому переработка записей/строк адаптера, похоже, не является решением. – caw

0

Вы пытались масштабировать растровое изображение? Вот как вы это делаете ...

BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeFile(filename, options); 
     options.inJustDecodeBounds = false; 
     options.inSampleSize = 2; // adjust sample size to whatever you want it to be 

     bitmap = BitmapFactory.decodeFile(filename, options); 
     if (bitmap != null && exact) { 
      bitmap = Bitmap.createScaledBitmap(bitmap, width, height, false); 
     } 

Здесь в методе BitmapFactory.decodeFile, создать уменьшенную Bitmap так, что он потребляет меньшую память, чем это было раньше, решить мою проблему, как насчет вашей?