2017-10-20 15 views
0

J'ai créé un list personnalisé, dont adapter qui contient trois composants titre de chanson, numéro de chanson et icône préférée . L'icône favorite est destinée à marquer ou à décocher l'élément favori de la liste. Veuillez regarder la vidéo ci-jointe pour comprendre quel est le problème.lorsque je fais défiler la liste personnalisée dans mon application Android puis l'icône préférée qui fait partie de l'adaptateur personnalisé change de son propre

Video

Lorsque je clique sur l'étoile, l'icône sélectionné obtient/désélectionnées et déclenche l'événement setOnFavoriteChangeListener. Dans le cas je vérifie l'état isFavorite et mettre à jour la base de données en conséquence. Voici le code complet de l'adaptateur:

public class song_index_adapter extends ArrayAdapter<song_index_model>{ //implements View.OnClickListener { 
private ArrayList<song_index_model> dataSet; 
Context mContext; 
private int lastPosition = -1; 

public song_index_adapter(ArrayList<song_index_model> data, Context context) { 
    super(context, R.layout.song_index_row, data); 
    this.dataSet = data; 
    this.mContext=context; 
} 
// View lookup cache 
private static class ViewHolder { 
    TextView txt_sno; 
    TextView txt_title; 
    MaterialFavoriteButton favorite; 
} 
@NonNull 
@Override 
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { 
    // Get the data item for this position 
    final song_index_model dataModel = getItem(position); 

    // Check if an existing view is being reused, otherwise inflate the view 
    final ViewHolder viewHolder; // view lookup cache stored in tag 

    final View result; 

    if (convertView == null) { 
     viewHolder = new ViewHolder(); 
     LayoutInflater inflater = LayoutInflater.from(getContext()); 
     convertView = inflater.inflate(R.layout.song_index_row, parent, false); 

     viewHolder.txt_sno = (TextView) convertView.findViewById(R.id.sno); 
     viewHolder.txt_title = (TextView) convertView.findViewById(R.id.songTitle); 
     viewHolder.favorite = (MaterialFavoriteButton) convertView.findViewById(R.id.indexfav); 

     result=convertView; 

     convertView.setTag(viewHolder); 
    } else { 
     viewHolder = (ViewHolder) convertView.getTag(); 
     result=convertView; 
    } 

    Animation animation = AnimationUtils.loadAnimation(mContext, (position > lastPosition) ? R.anim.up_from_bottom : R.anim.down_from_top); 
    result.startAnimation(animation); 
    lastPosition = position; 

    viewHolder.txt_sno.setText(dataModel.getSno()); 
    viewHolder.txt_title.setText(dataModel.getTitle()); 

    //--- following conditional statements take care to 
    //--- not to show a star with the index letter 
    if(viewHolder.txt_sno.getText().toString().equals("")) 
     viewHolder.favorite.setVisibility(View.GONE); 
    else 
     viewHolder.favorite.setVisibility(View.VISIBLE); 

    viewHolder.favorite.setFavorite(dataModel.getFav()); 

    int fsize = (gvar.fontsize * gvar.fontstep) + gvar.fontmin; 
    viewHolder.txt_title.setTextSize(fsize); 
    viewHolder.txt_sno.setTextSize(fsize); 

    viewHolder.favorite.setOnFavoriteChangeListener(new MaterialFavoriteButton.OnFavoriteChangeListener() { 
     @Override 
     public void onFavoriteChanged(MaterialFavoriteButton buttonView, boolean isfavorite) { 
      DBHelper db = new DBHelper(mContext); 
      SQLiteDatabase sdb = db.getWritableDatabase(); 

      boolean isUpdate = db.updateData(gvar.table,dataModel.getSno(),dataModel.getTitle(),dataModel.getSong(),dataModel.getCategory(),isfavorite); 
      if(!isUpdate) 
       Toast.makeText(mContext, "Song Selection could not be saved", Toast.LENGTH_SHORT).show(); 
      else { 
       Toast.makeText(mContext, "Updated " + dataModel.getSno(), Toast.LENGTH_SHORT).show(); 
       Log.e("UPDATED", dataModel.getSno() + " " + isfavorite); 
      } 
     } 
    }); 
    return convertView; 
} 

}

Cet événement est à l'intérieur du fichier adapter qui est situé sur la listview et il vérifie essentiellement l'état de la star préférée et mettre à jour le statut de la chanson dans la base de données. Vous pouvez voir les messages Toast qui demandent la mise à jour.

Mon problème est que même si je fais simplement défiler vers le haut et vers le bas sans appuyer sur l'icône étoile, alors l'événement setOnFavoriteChangeListener continue à se déclencher. Cela peut être vu dans les messages Toast et dans les enregistrements Log. Je joins également un instantané des enregistrements du journal que vous pouvez voir. Log record

Personnellement, j'ai changé l'icône favorite des seules chansons n ° 9 et 42 au début et 35 à la fin. Entre les deux, je n'ai fait que défiler de haut en bas et vous pouvez voir comment la mise à jour se passe d'elle-même.

Mon but est de marquer la liste des objets favoris.

Pourquoi le setOnFavoriteChangeListener se déclenche-t-il sans que je le touche?

Existe-t-il une autre méthode pour marquer les éléments favoris d'une liste et les enregistrer dans la base de données.

Merci à l'avance

+0

Pouvez-vous poster votre code d'adaptateur complet? Cela aiderait certainement. –

+0

Voici le code de l'adaptateur complet – pamo

+0

Je ne vois aucun code d'adaptateur. –

Répondre

0

Je pense que j'ai compris votre problème. Cela a à voir avec le fait que vous êtes en train de recycler vos articles ListView. Pendant le chargement initial tout fonctionne bien et rien n'est sélectionné et l'appel dataModel.getFav() renvoie false alors quand votre appel viewHolder.favorite.setFavorite() le MaterialFavoriteButton ne se déclenche pas, il est défini sur OnFavoriteChangeListener. La raison en est que, en interne, il vérifie si le nouvel état favori est différent du dernier en tant qu'optimisation pour éviter un travail inutile (I checked the source code). Mais, une fois que vous faites une sélection, votre onFavoriteChanged sera déclenché car le nouvel état est différent et vous stockez ensuite les valeurs dans votre base de données. Votre problème se pose lorsque vous commencez à faire défiler, puisque votre vue est recyclée, l'état favori de MaterialFavoriteButton sera défini, mais lorsque vous appelez dataModel.getFav(), il retournera false et changera l'état favori de MaterialFavoriteButton à false. Ainsi, votre ancien OnFavoriteChangeListener de MaterialFavoriteButton se déclenchera à nouveau (ce qui explique pourquoi le bouton n'est pas activé). Il met également à jour votre base de données avec son précédent dataModel (NOTE: c'est un problème de fermeture) c'est pourquoi vous le voyez utiliser le texte d'une vue qui a défilé à l'écran. La raison pour laquelle l'ancien OnFavoriteChangeListener est appelé parce que la vue est en cours de recyclage et possède toujours l'instance que vous lui avez transmise lors du chargement initial.Donc, une fois que toutes les vues sont remplies pour remplir tout l'écran, si vous faites défiler la première pour quitter l'écran supérieur, vous passerez à getView() en tant que convertView.Vous devez déplacer l'appel viewHolder.favorite.setOnFavoriteChangeListener avant le setFavorite () appel. Si vous placez une instruction de débogage dans le code et parcourez l'appel de viewHolder.favorite.setFavorite(), vous devriez voir de quoi je parle. J'espère que tout cela fait depuis pour vous. Sinon, commentez et j'essaie de vous donner plus d'aide. Ma solution recommandée serait de garder les écritures de base de données jusqu'à ce qu'un bouton de sauvegarde soit pressé ou que l'activité/fragment soit interrompue ou arrêtée et stocke simplement l'état préféré dans une ArrayList qui est accédée en utilisant l'argument de position getView (...) . Ceci est beaucoup plus efficace car vous n'aurez pas à accéder constamment à la base de données à chaque fois que vous faites défiler ListView.