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

Я не совсем уверен, что ViewPager с универсальным загрузчиком изображений может/должен использоваться в качестве альтернативы интерфейсу, подобному галерее, поскольку я столкнулся с ошибкой нехватки памяти при загрузке изображений с SD-карты и просмотре их в полноэкранном режиме. Независимо от того, какой номер, он отлично работает с GridView, но при просмотре изображений на пейджере просмотра каждое растровое изображение продолжает потреблять много памяти, и после 10 или около того изображений выдается ошибка нехватки памяти.

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

Я не знаю, использую ли я неправильные конфигурации или что, но я потратил на это много времени и немного застрял, любая помощь / совет будут оценены.

Конфигурации для ImageLoader:

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
            .memoryCache(new WeakMemoryCache())
            .denyCacheImageMultipleSizesInMemory()
            .discCacheFileNameGenerator(new Md5FileNameGenerator())
            .imageDownloader(new ExtendedImageDownloader(getApplicationContext()))
            .tasksProcessingOrder(QueueProcessingType.LIFO)
//          .enableLogging() // Not necessary in common
            .build();

Параметры отображения изображения:

options = new DisplayImageOptions.Builder()
            .showImageForEmptyUri(R.drawable.image_for_empty_url)
            .resetViewBeforeLoading()
            .imageScaleType(ImageScaleType.IN_SAMPLE_INT)
            .bitmapConfig(Bitmap.Config.RGB_565)
            .displayer(new FadeInBitmapDisplayer(300))
            .build();

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

РЕДАКТИРОВАТЬ: я знаю, что это утечка памяти, невидимые представления уничтожаются, когда они должны быть, но память не освобождается должным образом. Вот реализация обратного вызова destroyItem, следуя советам, данным в разных вопросах, но все еще не могу найти утечку памяти.

@Override
        public void destroyItem(View container, int position, Object object) {
//          ((ViewPager) container).removeView((View) object);
            Log.d("DESTROY", "destroying view at position " + position);
            View view = (View)object;
            ((ViewPager) container).removeView(view);
            view = null;
        }

person Faraz Hassan    schedule 19.02.2013    source источник


Ответы (7)


Попробуйте применить следующие предложения:

  1. Используйте 1_
  2. Включите кэширование на диске (в параметрах отображения).
  3. Наконец, попробуйте использовать .discCacheExtraOptions(maxImageWidthForDiscCache, maxImageHeightForDiscCache, CompressFormat.PNG, 0);
person nostra13    schedule 24.02.2013
comment
Как я уже упоминал выше, я заставил его работать, используя реализацию, упомянутую в ссылке на проблемы с github. Теперь это привело к другой ошибке: всякий раз, когда я удаляю изображение, возникает исключение (исключение из-за недопустимого состояния, ImageView больше не существует, больше не следует использовать этот PhotoViewAttacher). Что странно, так это то, что я возвращаю POSITION_NONE в getItemPosition, не лучшую из реализаций, но достаточно хорошую для моего случая, есть идеи, почему это происходит здесь? - person Faraz Hassan; 26.02.2013
comment
для вашего нового исключения см. прикрепленный патч: github.com/chrisbanes/PhotoView/pull/34< /а> - person shem; 03.03.2013
comment
Нет, бесполезно, все равно вылетает. То же исключение при изменении страницы. - person Faraz Hassan; 05.03.2013
comment
Imageloader по-прежнему дает мне OOM с ViewPager независимо от конфигурации. я загружаю только jpg ‹100Ko каждый магазин на SD-карту - person Damien Locque; 19.06.2014
comment
Попробуйте отключить кеширование в памяти (в DisplayImageOptions. - person nostra13; 19.06.2014

Вероятно, это не лучшая реализация для ее решения, но она сработала для меня. Удалить ImageViews недостаточно, поэтому я решил переработать растровые изображения в 'destroyItem':

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    View view = (View) object;
    ImageView imageView = (ImageView) view.findViewById(R.id.image);
    if (imageView != null) {
        Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
        bitmap.recycle();
        bitmap = null;
    }
    ((ViewPager) container).removeView(view);
    view = null;
}

Это не очищает последние 3 активные страницы, когда вы покидаете активность, хотя я надеюсь, что GC позаботится о них.

person txuslee    schedule 12.03.2013
comment
Учтите, что я не использую ImageLoader.cacheMemory. Если это проблема. - person txuslee; 12.03.2013
comment
разве этого недостаточно? @Override public void destroyItem(View collection, int position, Object view) { ((ViewPager) collection).removeView((View) view); } - person Sazzad Hissain Khan; 10.11.2013
comment
Должно быть, но не хватило. Переработка растрового изображения решила мои сбои, хотя я также считаю, что это не очень ортодоксальный метод. - person txuslee; 11.11.2013

Просто публикую это, потому что этот вопрос возникает в Google при поиске UIL и OOP. У меня были проблемы с ООП независимо от конфигурации, все мои проблемы решили два класса RecyclingImageView и RecyclingBitmapDrawable из этот пример проекта.

person fweigl    schedule 26.03.2013

Я также использовал ту же библиотеку и имел ту же ошибку. В качестве решения я создал sparseArray для хранения экземпляров photoView. И используйте это так:

 private SparseArray<PhotoView> photoViewHolder;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
       ...

       photoViewHolder = new SparseArray<PhotoView>();
       ...
 }

private class GalleryPagerAdapter extends PagerAdapter {

@Override
public View instantiateItem(ViewGroup container, int position) { 

        PhotoView photoView = new PhotoView(container.getContext());

        ImageHolder holder = new ImageHolder();
        holder.position = position;
        holder.loaded = false;

        photoView.setTag(holder);
        photoViewHolder.put(position, photoView);

                    // I used LazyList loading
        loader.DisplayImage(items.get(position), photoView);

        // Now just add PhotoView to ViewPager and return it
        container.addView(photoView, LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT);

        return photoView;
    }

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((View) object);
    photoViewHolder.remove(position);
}

@Override
public boolean isViewFromObject(View view, Object object) {
    return view == object;
}

}

И для обработки слушателя viewPager:

   pager.setOnPageChangeListener(new OnPageChangeListener() { 

    @Override
    public void onPageScrollStateChanged(int position) { 

    } 

    @Override
    public void onPageScrolled(int position, float arg1, int arg2) { 

    } 

    @Override
    public void onPageSelected(int position) { 
        if(photoViewHolder.get(position) != null) {
            ImageHolder holder = (ImageHolder)photoViewHolder.get(position).getTag();
            // Do something...
        }
    } 
});

Надеюсь это поможет...

person yahya    schedule 07.03.2013
comment
Не совсем :/ Проблема не устранена :S - person Faraz Hassan; 12.03.2013
comment
Вы уже сделали этот шаг, верно? github.com/xeodou/PhotoView/commit/ - person yahya; 12.03.2013
comment
да, но это не имело никакого эффекта, позвольте мне поделиться кодом активности, где я все это делаю. И, может быть, вы можете сказать мне, что я делаю неправильно - person Faraz Hassan; 12.03.2013
comment
Не видите, что вы сохраняете экземпляр фотопросмотров, как я описал? - person yahya; 13.03.2013
comment
есть идеи обо всем этом? Я застрял здесь :/ - person Faraz Hassan; 15.03.2013
comment
Еще не использовал эту библиотеку таким образом, поэтому я не уверен, что не так. Но я постараюсь проверить ваш код, как только у меня будет свободное время :) - person yahya; 16.03.2013
comment
о, я только что понял, что вы, возможно, работаете над неправильной проблемой, я упомянул в одном из комментариев ранее к другому ответу, что исходная проблема была ИСПРАВЛЕНА, когда я использовал этот патч: github.com/chrisbanes/PhotoView/pull/34, но это добавило ошибку в функцию удаления. Проблема в том, что когда изображение удаляется из галереи, оно удаляется с SD-карты, но представление не уничтожается и остается там, и если я заставляю его инициализировать все представления с помощью POSITION_NONE, это дает эту ошибку , надеюсь, это прояснит ситуацию, если вы все еще занимаетесь проблемой нехватки памяти. - person Faraz Hassan; 18.03.2013
comment
Теперь я понял, я думал, что не должно быть никаких проблем ... хм ... так что ваша проблема совершенно другая. Ну... Тогда я понятия не имею, извините. - person yahya; 18.03.2013

Я использовал реализацию kutothe со страницы проблем github.

person Faraz Hassan    schedule 21.02.2013
comment
к сожалению ссылка утеряна - person Youngjae; 19.05.2015

У меня возникла эта проблема, когда я просто установил для Uri значение ImageView с помощью: iv.setImageURI(Uri.fromFile(imgFile)); У меня была такая же проблема с универсальным загрузчиком изображений, и я даже искал другие загрузчики изображений и нашел еще один хороший, который называется "Picasso", но у него была такая же проблема.

Итак, что сработало для меня, так это использование GestureImageView и установка gesture-image:recycle в true через XML и загрузка изображений с помощью следующий код:

            Drawable yourDrawable = null;

            try {
                InputStream inputStream = getActivity().getContentResolver().openInputStream(Uri.fromFile(img));
                yourDrawable = Drawable.createFromStream(inputStream, Uri.fromFile(img).toString() );
                inputStream.close();
            } catch (FileNotFoundException e) {
                yourDrawable = getResources().getDrawable(R.drawable.ic_launcher);
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (yourDrawable != null)
                iv.setImageDrawable(yourDrawable);

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

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

Надеюсь, я помог.

person Amjad Abu Saa    schedule 10.09.2013

Я знаю, что уже поздно, но, возможно, мой ответ сэкономит чье-то время. После многих часов попыток решить эту проблему (почти каждый ответ был найден в переполнении стека) я, наконец, решил ее с помощью библиотеки изображений Fresco. Это библиотека, написанная Facebook, и ее основная цель — эффективно использовать память. Это действительно здорово, и моя ошибка нехватки памяти исчезла. Я настоятельно рекомендую использовать его.

http://frescolib.org/

person Jesus Christ    schedule 21.01.2016
comment
Ответ не связан с заданным вопросом. Правда, это альтернативная библиотека, которую можно было бы использовать, но она не решает упомянутую здесь проблему. - person Faraz Hassan; 09.03.2016
comment
Я знаю, но я написал это, потому что у меня была точно такая же проблема с UIL и View Pager. Я трачу слишком много часов, чтобы исправить это, и ошибка нехватки памяти все еще возникает. После того, как я внедрил библиотеку Fresco (у меня ушло около 10 минут), проблема больше НИКОГДА не возникала. Добавление этой библиотеки не оказало негативного влияния на мой проект — худшее, что вам нужно сделать, это заменить ImageView на собственное представление изображений Fresco, и это все еще легко. Я заменил UIL на Fresco, и у меня не было с ним проблем. Он прост в использовании и кажется более удобным для памяти. Вот почему я так рекомендую его, просто попробуйте :) - person Jesus Christ; 22.03.2016