2010-09-22 3 views
6

Ho implementato le immagini con caricamento lento nel mio ListView. Io uso un AsyncTask per scaricare l'immagine da Internet e collegarla a ImageView in UIThread.Lazy-loading images in ListView su Android

Funziona eccetto che quando si scorre il ListView variano velocemente, le immagini scaricate a volte sono vincolate agli elementi errati nell'elenco.

Immagino che il problema derivi dal riutilizzo di convertView nello BaseAdapter. Qualche idea per risolverlo?

Molte grazie.

EDIT: inserisco la risposta come segue:

public void setBitmap(int position, Bitmap image) { 
    View itemView = mListView.getChildAt(position - mListView.getFirstVisiblePosition()); 
    if (itemView != null) { 
     ImageView itemImageView = (ImageView) itemView.findViewById(R.id.item_imageview); 
     itemImageView.setImageBitmap(image); 
    } 
} 
+0

ho provato l'esempio qui http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html Funziona, ma ancora avuto la possibilità di legare l'immagine sbagliata. Il trucco confrontare l'istanza del compito sembra la stessa della risposta di Janusz. Ma usa un riferimento debole per contenere l'istanza di ImageView. Hai bisogno di scavare più a fondo. Qualche idea? – shiami

risposta

2

Creare una funzione chiamata void setBitmap(Bitmap bitmap, int position) o simili nel vostro adattatore. Lascia che il tuo AsyncTask chiami questo metodo quando è disponibile una nuova bitmap. Questo metodo può quindi chiamare notifyDataSetChanged() nella stessa UI-Thread per garantire che le visualizzazioni vengano aggiornate. Tenere i riferimenti alle viste in un adattatore (anche tenendoli in un AsyncTask) è pericoloso!

+0

Questo non è il problema che ha lo shiami. Sta riutilizzando le viste che hanno un'immagine impostata e poiché l'immagine corretta è impostata in un'attività asincrona viene mostrata la vecchia immagine fino a quando la nuova immagine non viene caricata, ecc. – Janusz

+1

Sì, lo è. Una volta ho lavorato a un progetto in cui si è verificato esattamente questo comportamento e l'utilizzo di setTag() o getTag() è stato solo una brutta soluzione. La soluzione era impostare la bitmap direttamente nel metodo getView(), che a sua volta è attivato da notifyDataSetChanged(). Ovviamente ciò porterà ad un aggiornamento di tutte le viste che sono visibili, il che potrebbe causare una balbuzie evidente. Per aggiornare solo una vista, questa soluzione potrebbe essere migliore: http: // StackOverflow.it/questions/3724874/android-update-single-item-in-list – mreichelt

+0

Grazie per il suggerimento. Ma dove posso ottenere l'istanza corretta della vista per legare l'immagine scaricata in base alla posizione data? – shiami

7

Ci sono due problemi che si presentano durante il caricamento lazy delle immagini in un ListView.

  1. Le vecchie immagini vengono visualizzate fino a quando non vengono caricate quelle nuove. È semplice impostare l'ImageView su un'immagine caricando la vista o impostandola su invisibile prima di iniziare il download dell'immagine.
  2. Il secondo problema è più difficile da risolvere. Immagina di scorrere molto velocemente nella tua lista. Ora le tue viste possono essere riciclate prima che il vecchio AsyncTask abbia finito di caricare l'immagine. Ora hai due attività in esecuzione che nel metodo onPostExecute imposteranno un'immagine alla visualizzazione di immagini. Ora per un breve periodo verrà mostrata l'immagine sbagliata fino al completamento della seconda attività o, ancora peggio, per alcuni motivi correlati alla rete che non terminano nell'ordine in cui sono stati avviati e l'immagine errata viene sovrascritta con l'immagine corretta. Per risolvere questo problema, devi controllare quale immagine deve essere visualizzata al termine dell'attività. Nella classe View sono due metodi per cose esatte come questo:

    setTag e getTag È possibile associare qualsiasi oggetto al ImageView che ti viene in mente. Nella maggior parte dei casi, utilizzo setTag per associare l'URL dell'immagine come stringa alla vista immagine prima di iniziare un'attività. Ora posso trasmettere getTag a una stringa al termine dell'attività e confrontare l'URL che dovrebbe essere visualizzato con l'URL scaricato e impostare l'immagine solo se necessario.

+0

Grazie! Il primo problema che hai descritto non sembra una soluzione per me. Perché il 'ImageView' verrà rilegato più volte quando lo scorrimento varia velocemente. Quindi l'impostazione di ImageView un'immagine di caricamento o invisibile non funziona. – shiami

+0

Il metodo getTag sembra non vincolerà 'ImageView' immediatamente perché il tag viene modificato dopo lo scorrimento. Viene aggiornato solo dopo aver fatto scorrere lentamente indietro e indietro. C'è qualche passo che sto facendo in modo errato? – shiami

+0

Non capisco cosa intendi con getTag non legherà immediatamente ImageView quindi non posso dire se stai facendo qualcosa di sbagliato. – Janusz