2013-05-08 25 views
7

Próbuję zintegrować Universal Image Loader z moją aplikacją na Androida. Ma GridView i pokazuje obrazy uzyskane z Internetu. Zaimplementowałem go za pomocą ArrayAdapter, który ładuje obrazy w getView() w zwykły sposób.Pamięć podręczna Universal Image Loader

Działa poprawnie pod względem prawidłowego wyświetlania obrazu. Ale znalazłem nieoczekiwane zachowanie podczas ładowania obrazów z pamięci podręcznej.

  1. Po uruchomieniu działania UIL ładuje obraz z Internetu lub z pamięci podręcznej na dysku, jeśli istnieje. (Oczywiście, oczekuje się zachowania).
  2. Przewijanie w dół GridView do momentu, aż pierwsza kolumna zniknie z ekranu i przewiń z powrotem na górę. W tym czasie obrazy w pierwszej kolumnie są ładowane z pamięci podręcznej dysku, a nie z pamięci podręcznej.
  3. Następnie przewijanie w dół iw górę. W tym czasie obrazy z pierwszej kolumny są ładowane z pamięci podręcznej.

Oczekuję, że obrazy będą ładowane z pamięci podręcznej przy drugim wyświetleniu, czyli w kroku 2 powyżej. Nie wiem, dlaczego pamięć podręczna dysku jest używana w tym przypadku.

Oto moje kody.

ImageLoaderConfiguration

ImageLoaderConfiguration mImageLoaderConfig = 
     new ImageLoaderConfiguration.Builder(getApplicationContext()) 
       .defaultDisplayImageOptions(defaultOptions) 
       .enableLogging() 
       .build(); 

DisplayImageOptions

DisplayImageOptions defaultOptions = 
     new DisplayImageOptions.Builder() 
       .cacheInMemory() 
       .cacheOnDisc() 
       .showImageForEmptyUri(R.drawable.empty_photo) 
       .showStubImage(R.drawable.empty_photo) 
       .displayer(new FadeInBitmapDisplayer(500)) 
       .build(); 

getView() w ArrayAdapter

if (convertView == null) { 
    convertView = (FrameLayout) LayoutInflater.from(getContext()) 
      .inflate(mLayoutId, null); 
    convertView.setLayoutParams(mImageViewLayoutParams); 
} else { // Otherwise re-use the converted view 
    convertView.findViewById(R.id.videoIconInThumbnail).setVisibility(View.GONE); 
} 

// Check the height matches our calculated column width 
if (convertView.getLayoutParams().height != mItemHeight) { 
    convertView.setLayoutParams(mImageViewLayoutParams); 
} 

ImageView image = (ImageView) convertView.findViewById(R.id.photoThumbnail); 
ImageLoader.getInstance().displayImage(thumbnailUrl, image, 
     new SimpleImageLoadingListener() { 

      @Override 
      public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { 
       Log.v(TAG, imageUri + " is loaded."); 
      } 
     }); 
return convertView; 

układ XML dla elementu w GridView

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

    <ImageView 
     android:id="@+id/photoThumbnail" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:scaleType="centerCrop" > 
    </ImageView> 

    <ImageView 
     android:id="@+id/videoIconInThumbnail" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="center" 
     android:src="@drawable/ic_play" 
     android:visibility="gone" > 
    </ImageView> 
</FrameLayout> 

Wersja UIL to 1.8.4. Testowana wersja Androida to 4.1.2.

Dodano wyjście logu UIL, gdy obraz jest ładowany trzy razy z opisaną wyżej operacją.

// Fist time of displaying 
I/ImageLoader(7404): Start display image task [http://xxx/yyy.JPG_1080x1776] 
I/ImageLoader(7404): Load image from disc cache [http://xxx/yyy.JPG_1080x1776] 
I/ImageLoader(7404): Subsample original image (x192) to x192 (scale = 1) [http://xxx/yyy.JPG_1080x1776] 
I/ImageLoader(7404): Cache image in memory [http://xxx/yyy.JPG_1080x1776] 
I/ImageLoader(7404): Display image in ImageView [http://xxx/yyy.JPG_1080x1776] 

// Second time of displaying 
I/ImageLoader(7404): ImageLoader is paused. Waiting... [http://xxx/yyy.JPG_358x357] 
I/ImageLoader(7404): Start display image task [http://xxx/yyy.JPG_358x357] 
I/ImageLoader(7404): Load image from disc cache [http://xxx/yyy.JPG_358x357] 
I/ImageLoader(7404): Subsample original image (x192) to x192 (scale = 1) [http://xxx/yyy.JPG_358x357] 
I/ImageLoader(7404): Cache image in memory [http://xxx/yyy.JPG_358x357] 
I/ImageLoader(7404): Display image in ImageView [http://xxx/yyy.JPG_358x357] 

// Third time of displaying 
I/ImageLoader(7404): Load image from memory cache [http://xxx/yyy.JPG_358x357] 

Dziękuję.

Odpowiedz

10

Dzieje się tak z powodu logiki UIL.

1) Pierwszy raz (ImageLoader.displayImage(...)) rozmiar ImageView jest nieznany, ponieważ nie został jeszcze narysowany na ekranie. Tak więc UIL uważa rozmiar ImageView jako pełny rozmiar ekranu, dekoduje obraz do Bitmapy tego rozmiaru (1080x1776, biorąc pod uwagę współczynnik proporcji) i buforuje tę Bitmapę w pamięci.

2) Drugi raz rzeczywisty rozmiar narysowanego ImageView jest znany (który jest mniejszy niż pełny ekran) i buforowana w wyszukiwarce UIL Bitmapa o odpowiednim rozmiarze, ale pamięć podręczna zawiera tylko poprzednią dużą bitmapę, która jest zbyt duża dla naszych potrzeb. Tak więc UIL ponownie dekoduje obraz na mniejszą mapę bitową i zapisuje go również w pamięci.

3) Poniższe ekrany używają już buforowanej bitmapy o potrzebnym rozmiarze.

Jest to po prostu cecha UIL.Zalecam korzystanie z konfiguracji denyCacheImageMultipleSizesInMemory() w celu zaoszczędzenia pamięci.

+0

dziękuję za odpowiedź. Rozumiem. Nie można w żaden sposób udostępnić tej samej pamięci podręcznej między obrazami o różnych rozmiarach, prawda? Jeśli tak, rozważę inne rozwiązania. Dziękuję. – KSJ

+0

Nie bardzo rozumiem, co masz na myśli mówiąc "udostępnij tę samą pamięć podręczną między obrazami w różnych rozmiarach, które mają być załadowane". – NOSTRA

+0

Mam na myśli, że UIL ładuje obraz z pamięci podręcznej, która została wcześniej buforowana, nawet jeśli rozmiary docelowe są różne. – KSJ

0

Odpowiedź NOSTRA jest słuszna, aby tego uniknąć (ładowanie z pamięci podręcznej dysku, gdy drugi raz zażąda obrazu), możesz pozwolić UIL poznać szerokość/wysokość ImageView przed deokracją obrazu, po prostu dodaj "android: maxWidth android: maxHeight "do ImageView

Powiązane problemy