очистка галереи при вызове Activity для Honeycomb, чтобы избежать OOME?

#android #bitmap #gallery #android-3.0-honeycomb #out-of-memory

#Android #растровое изображение #Галерея #android-3.0-honeycomb #нехватка памяти

Вопрос:

Я создаю программу просмотра книг для Android 3.0 Honeycomb. Он отлично работает на Samsung Galaxy Tab, но получает много ошибок OutOfMemoryErrors на Motorola Xoom версии 3.0.1. Оба устройства имеют 48 МБ места в куче виртуальной машины.

У меня есть 2 действия:

BookActivity — имеет SlowGallery , который загружает изображения 1280×640 и небольшую галерею, которая загружает изображения 160×80.

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

BitmapActivity — имеет один, ImageView который загружает изображение размером 4488×2244, и небольшую галерею, которая загружает изображения размером 160×80. Уменьшение размера изображения не является вариантом, поскольку пользователь намеревается увеличить изображение до 100%.

Я ввел это в метод загрузки растрового изображения, чтобы уменьшить растровое изображение до 16-битного:

 BitmapFactory.Options o2 = new BitmapFactory.Options();
if (compressColor) o2.inPreferredConfig = Bitmap.Config.RGB_565;
o2.inPurgeable = true;
o2.inInputShareable = true;
o2.inSampleSize = (int) scale;
b = BitmapFactory.decodeStream(fis, null, o2);
  

Когда я дважды касаюсь галереи BookActivity, она вызывает BitmapActivity, передавая соответствующий номер изображения для открытия. Я могу проделать это 1-3 раза, введя BitmapActivity, затем щелкнув назад, прежде чем появится ошибка OutOfMemoryError.

При двойном нажатии на галерею вызывается PageAdapter.purge(), который, как представляется, визуально выгружает изображения галереи.

Это BookActivity.PageAdapter, который является адаптером для SlowGallery:

 private class PageAdapter extends BaseAdapter {
private final LayoutInflater mInflater;
private Page currentPage;
private boolean purge = false;
private WeakReference<Bitmap> weakReferenceBitmap;
public PageAdapter(Context context) {
    mInflater = LayoutInflater.from(context);
}
public void unpurge() {
    purge = false;
    notifyDataSetChanged();
}   
public void purge() {
    purge = true;
    holder = null;
    notifyDataSetChanged();
}       
@Override
public int getCount() {
    if (listPages==null || purge) return 0;
    return listPages.size();
}
@Override
public Object getItem(int position) {
    return null;
}
@Override
public long getItemId(int position) {
    return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.gallery_pages, null);
        holder = new ViewHolderIssues();
        holder.image = (ImageView) convertView.findViewById(R.id.ImageViewPage);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolderIssues) convertView.getTag();
    }
    if (position < listPages.size()) {
        currentPage = listPages.get(position);
        File f = new File(Engine.PATH   currentPage.getImageMedium());
        if (!purge) {
            if (!f.exists()) {
                holder.image.setImageResource(R.drawable.loading);
                Engine.triggerTrickle(currentPage.getImageMedium(), WeightedAsset.IMAGE_MEDIUM, getApplicationContext());                   
            } else {
                weakReferenceBitmap = new WeakReference<Bitmap>(Engine.loadImageFromBitmap(currentPage.getImageMedium(), screenWidth, 1, true));
                if (weakReferenceBitmap.get()!=null) {
                    holder.image.setImageBitmap(weakReferenceBitmap.get());
                } else {
                    holder.image.setImageDrawable(null);
                }
            }
        } else {
            weakReferenceBitmap.clear();
            holder.image.setImageDrawable(null);
            holder = null;
            System.gc();
        }
        f = null;
    }
    return convertView;
}
}
  

Просматривая файл HPROF под деревом Dominator, кажется, что он BookActivity.SlowGallery все еще существует, даже когда я нахожусь в BitmapActivity . При вводе BookActivity , SlowGallery занимает 3,2-6,5 МБ (1,6 МБ на изображение), но в BitmapActivity он занимает 1,6 МБ ( SlowGallery.LinearLayout.ImageView.BitmapDrawable = 1,6 МБ). Как мне избавиться от SlowGallery ?

Ответ №1:

Ах, там какой-то сложный фрагмент кода. Слабые ссылки могут помочь, но в целом, при использовании ImageView в адаптере, прежде чем устанавливать новое растровое изображение, вы должны извлечь старое растровое изображение и затем вызвать Bitmap.recycle() . Вы также должны сделать это с BitmapActivity, когда оно destroy редактируется. Это должно сделать большую часть того, что вам нужно.

Комментарии:

1. (поле «Использовать ответ на вопрос» отключено)

Ответ №2:

Спасибо! Мне удалось провести рефакторинг, чтобы переработать растровое изображение. Тем не менее, галерея все еще зависала, потому что BitmapActivity.onCreate вызывалась раньше BookActivity.onDestroy . Если бы я вызвал функцию purge (), мне удалось бы очистить большую ее часть, за исключением просмотренного / выбранного вида (поддерживается Gallery прослушивателем двойного нажатия!)

Затем я удалил проклятую галерею и поместил свою собственную ImageView imageviewCurrentPage ImageView imageviewFlipperPage ) и анимировал их при входе и выходе. Страница imageviewFlipperPage будет немедленно уничтожена после завершения анимации, поэтому я гарантированно загружал максимум только 2 растровых изображения. Gallery Может занимать до ПЯТИ просмотров с выбранными, нажатыми представлениями и т.д.

Я также добавил это для дальнейшей изоляции использования памяти:

 <activity android:name=".BitmapActivity" android:process=":BitmapActivity" ...>
  

Однако возникла сложность в том, что статические классы не являются общими для всех процессов. Следовательно, если в BookActivity я сделал движок.SESSION_ID=5 где SESSION_ID является статическим, я не смог бы прочитать его в движке BitmapActivity.SESSION_ID.