Domanda

Questo è uno scenario molto comune: visualizzare le immagini in un ListView che devono essere scaricate da Internet.

In questo momento ho una sottoclasse personalizzata di ArrayAdapter che uso per ListView. Nella mia implementazione getView () di ArrayAdapter, ho generato un thread separato per caricare un'immagine. Al termine del caricamento, cerca ImageView appropriato e imposta l'immagine con ImageView.setImageDrawable (). Quindi la soluzione che ho usato è in qualche modo simile a questa: Caricamento pigro di immagini in ListView

Il problema che sto riscontrando è che non appena effettuo la chiamata a setImageDrawable () su ImageView, ListView aggiorna in qualche modo tutte le righe attualmente visibili nell'elenco! Ciò si traduce in una specie di ciclo infinito:

  1. getView () si chiama
  2. Il thread
  3. viene generato per caricare l'immagine
  4. l'immagine è caricata; setImageDrawable () viene chiamato su ImageView
  5. ListView lo raccoglie per qualche motivo e si aggiorna da solo
  6. Per l'aggiornamento di ListView, viene chiamato getView () per ogni riga visibile, quindi torniamo al passaggio 1 e il tutto si ripete

Per quanto posso vedere, la soluzione proposta in " Android - Come posso fare un carico pigro di immagini in ListView " (vedi link sopra) semplicemente non funziona. Potrebbe sembrare, ma funzionerà molto lentamente perché in background continua a ricaricare le righe attualmente visibili.

Qualcuno ha riscontrato questo prima e / o aveva una soluzione per questo?

È stato utile?

Soluzione

Nella soluzione collegata, fetchDrawableOnThread () dovrebbe essere chiamato solo se la vista non ha già il disegnabile corretto.

Una vista non ha un disegno se getDrawable () restituisce null.

Se stai riutilizzando gli slot, hai bisogno di andare oltre e gestire lo stato. Se le tue viste hanno una variabile membro che memorizza l'URL e un valore booleano per dire se è caricato, sarebbe facile sapere se chiamare fetchDrawableOnThread () o no, ad esempio.

Suppongo che il toString () del drawable abbia dettagliato il percorso da cui è stata caricata l'immagine. (In caso contrario, è possibile sottoclassare il disegno restituito per renderlo tale). In questo caso, potresti evitare il booleano descritto sopra e fare semplicemente un confronto per determinare se è il disegno giusto o se recuperare un sostituto.

Inoltre, getView () su una riga visibile dovrebbe garantire che quelli che non sono più visibili vengano scaricati, per evitare l'esaurimento della memoria. Una finezza sarebbe quella di spostare le immagini non più visibili in riferimenti morbidi (quindi vengono scaricate quando è necessaria la memoria) come notato da un altro poster sul thread originale.

Altri suggerimenti

Ho usato il codice nel seguente link: un'altra domanda di StackOver

Ho apportato piccole modifiche per risolvere il problema di visualizzazione del riciclaggio. Ho impostato l'URL dell'immagine su Tag di imageview nell'adattatore. Il seguente codice contiene la mia soluzione che risolve il problema del riciclaggio:

public void fetchDrawableOnThread(final String urlString, final ImageView imageView,Drawable drw) {

    imageView.setImageDrawable(drw);//drw is default image
    if (drawableMap.containsKey(urlString)) {
        if(imageView.getTag().toString().equals(urlString))
        {
            imageView.setImageBitmap(drawableMap.get(urlString));
            imageView.invalidate();
            return;
        }

    }

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            BitmapWrapper wrapper = (BitmapWrapper)message.obj;
            if(wrapper.imageurl.equals(imageView.getTag().toString()))
            {
                imageView.setImageBitmap((Bitmap)wrapper.bitmap);
                imageView.invalidate();
            }

        }
    };

    Thread thread = new Thread() {
        @Override
        public void run() {
            //TODO : set imageView to a "pending" image

            Bitmap drawable = fetchDrawable(urlString);
            BitmapWrapper wrapper = new BitmapWrapper();
            wrapper.bitmap = drawable;
            wrapper.imageurl = urlString;
            Message message = handler.obtainMessage(1, wrapper);
            handler.sendMessage(message);
        }
    };
    thread.start();
}


    public class BitmapWrapper
{
    public Bitmap bitmap;
    public String imageurl;
}

Ho avuto lo stesso problema.

Dopo quasi 2 giorni di intenso debug / ottimizzazione e cercando di capire, perché il mio getView () viene chiamato ripetutamente per tutte le visualizzazioni quando si utilizza setImageBitmap () in una riga, ho trovato una soluzione sporca:

1) Estendi un ImageView personalizzato che usi per tutte le immagini nella tua lista

2) in questo ImageView sovrascrive il metodo

@Override
public void requestLayout()
{ 
  return; 
}

3) Sporco, ma per me funziona

4) Profitto;)

Ho un ThumbnailAdapter che racchiude questo intero schema che può aiutare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top