2

J'ai vu quelques questions comme celle-ci, mais je semble avoir un problème légèrement différent. Alors j'ai pensé que je demanderais à quelqu'un ici.Mauvaises images Charges lors du chargement des images dans listview

J'ai une listview personnalisée avec un textview et une imageview. Je charge des images à l'aide d'une tâche asynchrone, puis je règle les images sur l'imageview dans ma méthode d'exécution postée. Mes images se chargent bien, mais certaines images sont remplacées par d'autres images. Mais après que toutes les images sont finies, chaque imageview a l'image correcte. Je n'arrive pas à comprendre pourquoi j'ai ce problème.

Voici mes classes de tâches adaptateur et asynchrone. Toute aide serait appréciée. J'ajoute maintenant une balise (La balise est le texte qui va dans les vues de texte respectives) et dans mon message j'exécute je vérifie si la balise est égale au texte de la vue. J'ai toujours le même problème qu'avant.

Voici ma classe Adaptateur:

public class CustomListAdapter extends ArrayAdapter<CustomList> { 

    Context context; 
    int layoutResourceId; 
    LinkedList<CustomList> data = null; 
    LinkedList<String> title_list = new LinkedList(); 

    LoadImage l; 
    CustomList cl; 
    ProgressBar pb; 
    HashMap <String, Bitmap> bitmap = new HashMap<String, Bitmap>(); 







    public CustomListAdapter(Context context, int layoutResourceId, LinkedList<CustomList> data, LinkedList<Bitmap> bitmap_list) { 
     super(context, layoutResourceId, data); 
     // TODO Auto-generated constructor stub 

     this.context = context; 
     this.layoutResourceId = layoutResourceId; 
     this.data = data; 

    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     // TODO Auto-generated method stub 

     View row = convertView; 
     CustomListHolder holder = null; 




     if(row == null){ 
      LayoutInflater inflater = ((Activity)context).getLayoutInflater(); 
      row = inflater.inflate(layoutResourceId, parent, false); 
      holder = new CustomListHolder(); 

      holder.text = (TextView)row.findViewById(R.id.txtTitle); 
      holder.thumbnail = (ImageView)row.findViewById(R.id.imgIcon); 
      holder.pb = (ProgressBar)row.findViewById(R.id.progressBar1); 

      row.setTag(R.id.id0, holder); 


      cl = data.get(position); 
      holder.text.setText(cl.title); 
      holder.thumbnail.setImageResource(R.drawable.icon); 
      holder.pb.setVisibility(View.VISIBLE); 


      row.setTag(R.id.id1,new String(cl.title)); 
      LoadImage li = new LoadImage(context, holder.thumbnail, cl.icon,cl.title, bitmap,holder.pb,row); 
      li.execute(cl.icon);   

     } 

     else{ 
      Log.e("Row not null","Inside"); 
      holder = (CustomListHolder)row.getTag(R.id.id0); 
      //row.getK 
      cl = data.get(position);   
      holder.text.setText(cl.title); 
      holder.thumbnail.setImageResource(R.drawable.icon); 
      holder.pb.setVisibility(View.VISIBLE); 
      if((Bitmap) bitmap.get(cl.title) == null){ 
       row.setTag(R.id.id1,new String(cl.title)); 
       LoadImage li = new LoadImage(context, holder.thumbnail, cl.icon,cl.title, bitmap,holder.pb,row); 
       li.execute(cl.icon); 


      } 
      else { 
       holder.thumbnail.setImageBitmap((Bitmap) bitmap.get(cl.title)); 
       holder.pb.setVisibility(View.GONE); 
      } 



     } 



     return row; 


    } 

    static class CustomListHolder 
    { 
     ImageView thumbnail; 
     TextView text; 
     ProgressBar pb; 
    } 


} 

Voici ma async classe de tâche:

LoadImage public class étend AsyncTask {

Context callingContext = null; 
ImageView view; 
String bits; 
public ProgressBar pb; 
HashMap<String, Bitmap> bitmap; 
String url; 
String text; 
View row; 



public LoadImage(Context c, ImageView view, String bits, String text, HashMap<String, Bitmap> bitmap, ProgressBar pb, View row){ 

    this.view = view; 
    this.bits = bits; // url for image 
    this.callingContext = c; 
    this.bitmap = bitmap; //hashmap 
    this.text = text;// title text 
    this.pb = pb; 
    this.row = row; 

} 



public Bitmap getBitmap(String data){ 

    Bitmap bitmap; 
    BitmapFactory.Options bmOptions; 
    bmOptions = new BitmapFactory.Options(); 
    bmOptions.inJustDecodeBounds = true; 
    Log.e("getBitmap",text); 

    try { 
     bitmap=null; 
     InputStream is=new URL(data).openStream(); 
     BitmapFactory.decodeStream(is, null, bmOptions); 
     is.close(); 
     BitmapFactory.Options o2 = new BitmapFactory.Options(); 
     o2.inSampleSize = 10; 
     is = new URL(data).openStream(); 
     bitmap = BitmapFactory.decodeStream(is, null, o2); 

     bitmap = Bitmap.createScaledBitmap(bitmap, 60, 60, true); 
     is.close(); 
     this.bitmap.put(text,bitmap); 
     return bitmap; 
    } catch (Exception ex){ 
     Log.e("Debug", ex.getMessage()); 
     return null; 
    } 

} 


@Override 
protected Bitmap doInBackground(String... arg0) { 
    // TODO Auto-generated method stub 
    Log.e("do In Bg",text); 
    Bitmap b = null;  

    if((Bitmap)bitmap.get(text) == null) 
     b = getBitmap(bits); 
    else 
     b =(Bitmap)bitmap.get(text); 

     return b; 
} 



@Override 
protected void onPostExecute(Bitmap result) { 
    // TODO Auto-generated method stub 
    super.onPostExecute(result); 
     if(row.getTag(R.id.id1).equals(text)){ 
      view.setImageBitmap((Bitmap)bitmap.get(text)); 
      pb.setVisibility(View.GONE); 
     } 




} 

}

CustomList est une classe avec 2 icône de cordes et titre. L'icône est l'URL de l'image et le titre est le texte de la vue.

+0

À quoi ressemble votre xml? Avez-vous une image temporaire dans la vue de l'image? Cela ressemble à ce que vous faites, et quand 'asynctask' est chargé, vous obtenez l'image correcte. – BlackHatSamurai

+1

Cela se produit-il uniquement lors du défilement? – Krylez

+0

@BlaineOmega - J'ai défini mon image pour être égale au lanceur Android pendant le chargement de l'image. Une fois le chargement terminé, le lanceur est remplacé par l'image. Je charge 2 images différentes disons a et b environ 10 fois. Dans ma listview, j'ai les images en alternance. Même après le chargement de l'image, parfois b prend la position de a et vice versa. Cependant, après que toutes les images sont complètement chargées, les images sont dans leur bonne position. –

Répondre

4

Je suis sûr que @Krylez allait vous dire la même chose: Dans un ListView, vos lignes sont recyclées. C'est ce que covertView vous donne et vous faites une ligne == null check. Si votre écran affiche 10 lignes à la fois, il a probablement environ 11 à 12 lignes en mémoire. Au fur et à mesure que vous faites défiler et qu'une rangée disparaît, elle est gardée en mémoire et vous est restituée avec les anciennes choses pour que vous puissiez vous repeupler. Disons que vous avez la cellule 1 ... Vous avez demandé bitmap 1. Ensuite, l'utilisateur la fait défiler hors de vue et il est recyclé en bitmap 12. Maintenant, la tâche bitmap 1 se termine et dessine car les références d'objet sont encore intact (jamais détruit). Donc, vous obtenez cet effet de mauvaises images montrant. J'ai utilisé une solution facile pour un projet iOS: utiliser des balises d'objet. Permettez-moi de vous expliquer:

Lorsque vous lancez une tâche comme LoadImage, étiquette de votre ligne avec un identifiant unique, vous pouvez identifier le bitmap et sa position de relation avec ...

row.setTag(new Integer(ID_THAT_IDENTIFIES_ROW_AND_BITMAP_RELATIONSHIP)) 

Quand il est temps de faire votre onPostExecute() dans votre tâche asynchrone, vérifiez si cet identifiant a changé. Si votre bitmap actuel ne correspond plus, ne faites rien car il y a probablement une autre tâche en attente pour le remplir.

J'espère que cela aide!

+0

Depuis que je vais la fixation d'un tag deux fois pour ma rangée (une fois pour le support et une fois pour l'entier) comment puis-je le précise pour me donner la valeur entière? –

+0

Oui. Il y a quelques autres choses que vous pouvez envisager. Lorsque vous avez affaire à une vue recyclé (convertView est non nul), pensez à appeler la méthode cancel() sur l'ancienne tâche async juste avant le tir hors un nouveau. Si vous ne faites pas cela, faire défiler une longue liste va consommer du temps CPU inutile. Une amélioration avancée, mais la peine serait de regarder dans un LRUCache: https://developers.google.com/events/io/sessions/gooio2012/103/ – Krylez

+0

Mon mauvais, il semblait travailler sur l'émulateur, mais pas sur l'appareil. J'ai mis à jour mon code. J'ai mis à jour mon code aussi. –

0

Mon avis dans ce cas est toujours de créer une nouvelle ligne.

LayoutInflater inflater = ((Activity)context).getLayoutInflater(); 
row = inflater.inflate(layoutResourceId, parent, false); 

Ne pas besoin d'utiliser le support (bien que cela semble bon pour lisse). Essayez-le.

Merci.

Questions connexes