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

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

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

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

Конфигурации для 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();

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

EDIT: я знаю, что это утечка памяти. Представления, которые не видны, уничтожаются, когда они должны быть, но память не освобождается, как следует. Это реализация обратного вызова 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;
        }

Ответ 1

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

  • Используйте ImageScaleType.EXACTLY
  • Включить кеширование на диске (в параметрах отображения).
  • Наконец, попробуйте использовать .discCacheExtraOptions(maxImageWidthForDiscCache, maxImageHeightForDiscCache, CompressFormat.PNG, 0);

Ответ 2

Вероятно, это не лучшая реализация, но для меня это работало. Удаление 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 позаботится о них.

Ответ 3

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

Ответ 4

Я также использовал одну и ту же библиотеку и имел ту же ошибку. В качестве решения я создал 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...
        }
    } 
});

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

Ответ 5

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

Ответ 6

У меня была эта проблема, когда просто устанавливали Uri на ImageView, используя: iv.setImageURI(Uri.fromFile(imgFile)); У меня была такая же проблема с Universal Image Loader, и я даже искал другие Image Loaders там, и нашел еще один хороший, получивший название 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, это будет лучшим решением.

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

Ответ 7

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

http://frescolib.org/