View Pager with Universal Image Loader Out of Memory Error

Nie jestem pewien, czy ViewPager z Universal Image Loader może / powinien być używany jako alternatywa dla interfejsu galerii, ponieważ napotkałem błąd braku pamięci podczas ładowania obrazów z karty SD i przeglądania ich w trybie pełnoekranowym. Bez względu na liczbę, działa to dobrze z GridView, ale podczas przeglądania obrazów w widoku Pager, każda bitmapa pożera dużo pamięci i po 10 lub tak obrazów, daje błąd out of memory.

Widziałem prawie wszystkie pytania, które zostały tutaj opublikowane, dotyczyły błędu Out of Memory podczas pracy z Universal Image Loader i w każdym z nich wystąpił błąd konfiguracji jako przyczyna.

Nie wiem, czy używam niewłaściwych konfiguracji lub co, ale zmarnowałem na to dużo czasu i trochę utknąłem, każda pomoc/porady będą mile widziane.

Konfiguracje dla 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();

Opcje wyświetlania obrazu to:

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();

Jestem używając przykładowego projektu, który został podany z biblioteką, ale te ustawienia też nie działają, po prostu zawiesza się po pewnym czasie. Domyślam się, że istnieje konkretna funkcja zwrotna, w której muszę przetwarzać bitmapy z widoków, z których nie są widoczne.

EDIT: wiem, że to wyciek pamięci, widoki, które nie są widoczne, są niszczone, kiedy powinny być, ale pamięć nie jest uwalniana tak, jak powinna. Heres implementacji wywołania zwrotnego destroyItem, postępując zgodnie z wskazówkami podanymi w różnych pytania, ale nadal nie można znaleźć wycieku pamięci.

@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;
        }
Author: Faraz Hassan, 2013-02-19

7 answers

Spróbuj zastosować następne sugestie:

  1. Użyj ImageScaleType.EXACTLY
  2. Włącz buforowanie na dysku (w opcjach wyświetlania).
  3. Wreszcie spróbuj użyć .discCacheExtraOptions(maxImageWidthForDiscCache, maxImageHeightForDiscCache, CompressFormat.PNG, 0);
 4
Author: NOSTRA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-24 16:13:56

To prawdopodobnie nie jest najlepsza implementacja do rozwiązania tego problemu, ale u mnie zadziałało. Usunięcie Imageviewów nie wystarczy, więc zdecydowałem się na recykling bitmap w '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;
}

To nie czyści ostatnich 3 aktywnych stron po opuszczeniu aktywności, chociaż mam nadzieję, że GC się nimi zajmie.

 5
Author: txuslee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-12 17:31:21

Po prostu zamieszczam to, ponieważ to pytanie pojawia się w Google podczas wyszukiwania UIL i OOP. Miałem problemy z OOP bez względu na konfigurację, co rozwiązało wszystkie moje problemy były dwie klasy RecyclingImageView i RecyclingBitmapDrawablez ten przykładowy projekt.

 2
Author: asco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-26 08:10:46

Używałem tej samej biblioteki i miałem ten sam błąd. Jako rozwiązanie stworzyłem sparseArray, aby zachować instancje photoView. I używaj go tak:

 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;
}

}

I do obsługi słuchacza viewpagera:

   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...
        }
    } 
});
Mam nadzieję, że to pomoże...
 1
Author: yahya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-07 13:48:54

Użyłem implementacji kutothe ze strony github issues.

 0
Author: Faraz Hassan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-21 14:32:33

Miałem taki problem gdy ustawiałem Uri na ImageView używając: iv.setImageURI(Uri.fromFile(imgFile)); Miałem ten sam problem z Universal Image Loader, a nawet Szukałem innych Image Loaderów i znalazłem inny dobry o nazwie " Picasso ", ale miał też ten sam problem.

Więc to, co mi się udało, to użycie GestureImageView i ustawienie gesture-image:recycle na true poprzez XML i załadowanie obrazów następującym kodem:

            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);

Powodem awarii i wystąpienia błędu OOM jest to, że bitmapy nie są poddawane recyklingowi, gdy obraz nie jest już wyświetlany na ekranie, w związku z czym występuje wyciek pamięci.

Jeśli istnieje inny sposób recyklingu bitmapy w normalnym ImageView, byłoby to lepszym rozwiązaniem.

Mam nadzieję, że pomogłem.
 0
Author: Amjad Abu Saa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-10 10:29:25

Wiem, że jest późno, ale może moja odpowiedź zaoszczędzi komuś czasu. Po wielu godzinach prób rozwiązania tego problemu (prawie każda odpowiedź znajduje się na stack overflow) w końcu rozwiązałem go z fresco image library. To lib napisany przez Facebook i jego głównym celem jest efektywne wykorzystanie pamięci. Jest naprawdę świetny i mój błąd z pamięci zniknął. Gorąco polecam korzystanie z niego.

Http://frescolib.org/

 -1
Author: Jesus Christ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-21 18:35:01