Fonctionnement du mécanisme de recyclage de ListView
Donc, j'ai ce problème que j'avais avant, et, naturellement, j'ai demandé de l'aide sur ici . La réponse de Luksprog était excellente parce que je n'avais aucune idée de la façon dont ListView et GridView se sont optimisés avec des vues de recyclage. Ainsi, grâce à ses conseils, j'ai pu changer la façon dont j'ai ajouté des vues à mon GridView. Le problème est maintenant, j'ai quelque chose qui n'a pas de sens. C'est mon getView
de mon BaseAdapter
:
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.day_view_item, parent, false);
}
Log.d("DayViewActivity", "Position is: "+position);
((TextView)convertView.findViewById(R.id.day_hour_side)).setText(array[position]);
LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.day_event_layout);
//layout.addView(new EventFrame(parent.getContext()));
TextView create = new TextView(DayViewActivity.this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 62, getResources().getDisplayMetrics()), 1.0f);
params.topMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
params.bottomMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
create.setLayoutParams(params);
create.setBackgroundColor(Color.BLUE);
create.setText("Test");
//the following is my original LinearLayout.LayoutParams for correctly setting the TextView Height
//new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getResources().getDisplayMetrics()), 1.0f)
if(position == 0) {
Log.d("DayViewActivity", "This should only be running when position is 0. The position is: "+position);
layout.addView(create);
}
return convertView;
}
}
le problème, c'est quand je fais défiler, ça arrive, et pas en position 0... On dirait la position 6 et la position 8, plus deux en position 8. Maintenant je suis toujours en train d'essayer de m'habituer à L'utilisation de ListView et GridView donc je ne comprends pas pourquoi cela se produit. Une des principales raisons pour lesquelles je pose cette question Est d'aider les autres qui ne sont probablement pas au courant de la vue de recyclage de ListView et GridView, ou la façon dont cet article le met, mécanisme de ScrapView.
Modifier Plus Tard
Ajouter un lien vers google IO talk qui est essentiellement tout ce dont vous avez besoin pour comprendre comment ListView fonctionne. Le lien était mort dans les commentaires. Donc user3427079 était assez gentil pour mettre à jour ce lien. Ici il est facile d'accès.
3 réponses
au départ, je n'étais pas non plus au courant du recyclage de listview et du mécanisme d'utilisation de convertview, mais après des jours entiers de recherche, je comprends à peu près les mécanismes de la vue liste en me référant à une image de android.amberfog
lorsque votre listview est rempli avec un adaptateur, il affiche essentiellement le nombre de lignes que le listview peut afficher à l'écran et le nombre de les lignes ne sont pas augmentées même si vous faites défiler la liste, il s'agit de l'astuce android utiliser de sorte que listview travailler plus efficace et rapide, Maintenant l'histoire intérieure de listview se référant à l'image comme vous pouvez le voir initialement la vue de liste a 7 articles visibles, si vous faites défiler vers le haut quand l'article 1 n'est plus visible getView () passer cette vue (item1) à recycler et vous pouvez utiliser
System.out.println("getview:"+position+" "+convertView);
dans votre
public View getView(final int position, View convertView, ViewGroup parent)
{
System.out.println("getview:"+position+" "+convertView);
ViewHolder holder;
View row=convertView;
if(row==null)
{
LayoutInflater inflater=((Activity)context).getLayoutInflater();
row=inflater.inflate(layoutResourceId, parent,false);
holder=new PakistaniDrama();
holder.tvDramaName=(TextView)row.findViewById(R.id.dramaName);
holder.cbCheck=(CheckBox)row.findViewById(R.id.checkBox);
row.setTag(holder);
}
else
{
holder=(PakistaniDrama)row.getTag();
}
holder.tvDramaName.setText(dramaList.get(position).getDramaName());
holder.cbCheck.setChecked(checks.get(position));
return row;
}
vous remarquerez d'abord dans votre logcat convertview est null pour toutes les lignes visibles, car initialement il n'y avait pas de vue(élément) dans recycler, donc votre getView() crée chaque nouvelle vue pour les éléments visibles, mais le moment où vous faites défiler votre article 1 enverra au Recycler avec son état(par exemple le texte de TextView et comme dans le cas de la mine si case à cocher est cochée, il sera également associé à la vue et stocker dans recycler). Maintenant quand vous faites défiler vers le haut/en bas de votre listview ne va pas créer une nouvelle vue il sera utilisez la vue(convert view) qui est déjà dans votre recycleur, dans votre Logcat vous remarquerez que convertView n'est pas null, c'est parce que votre nouvel item 8 sera dessiné en utilisant convertview, c'est-à-dire essentiellement il prend la vue item 1 du recycleur et du gonfleur à la place de l'item 8, et vous pouvez observer que comme dans le code de mine si vous aviez une case à cocher et si vous la cochez à la position 0(disons que l'item 1 a aussi une case à cocher et vous l'avez cochée) donc quand vous faites défiler vers le bas vous verrez l'article 8 la case à cocher est déjà cochée, c'est pourquoi listview réutilise la même vue et ne crée pas de nouvelle vue pour vous en raison de l'optimisation des performances.
choses Importantes
1 . Ne jamais définir le layout_height
et layout_width
de votre listview à wrap_content
comme getView()
forcera votre adaptateur pour obtenir un enfant pour mesurer la hauteur des vues à dessiner dans la vue liste et peut causer certains comportement inattendu comme le retour de convertview même la liste n'est pas scrolled.toujours utiliser match_parent
ou fixe largeur/hauteur.
2 . Si vous voulez utiliser une mise en page ou une vue après votre vue liste et la question pourrait venir dans votre esprit si je mets le layout_height
à fill_parent
la vue après la vue liste ne se montrera pas comme il descend l'écran, de sorte qu'il est préférable de mettre votre listview à l'intérieur d'une mise en page.Par exemple la disposition linéaire et régler la hauteur et largeur de cette disposition à partir de votre exigence et de faire la hauteur et largeur attribut de votre listview à partir de votre disposition(comme si votre largeur de la disposition est 320 et la hauteur est 280) alors votre listview devrait avoir la même hauteur et largeur . Cela indiquera à getView() la hauteur et la largeur exactes des vues à rendre, et getView () n'appellera pas encore et encore quelques lignes aléatoires, et d'autres problèmes comme le retour de la vue convert avant même que le scrolling n'arrive, je l'ai testé moi-même, à moins que mon listview ne soit à l'intérieur de la lineaLayout, il avait aussi des problèmes comme répéter l'appel de vue et la vue convert as, mettre Listview à L'intérieur de la LinearLayout a fonctionné comme par magie pour moi.(Je ne savais pas pourquoi)
01-01 14:49:36.606: I/System.out(13871): getview 0 null
01-01 14:49:36.636: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.636: I/System.out(13871): getview 1 android.widget.RelativeLayout@406082c0
01-01 14:49:36.646: I/System.out(13871): getview 2 android.widget.RelativeLayout@406082c0
01-01 14:49:36.646: I/System.out(13871): getview 3 android.widget.RelativeLayout@406082c0
01-01 14:49:36.656: I/System.out(13871): getview 4 android.widget.RelativeLayout@406082c0
01-01 14:49:36.666: I/System.out(13871): getview 5 android.widget.RelativeLayout@406082c0
01-01 14:49:36.666: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.696: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.706: I/System.out(13871): getview 1 null
01-01 14:49:36.736: I/System.out(13871): getview 2 null
01-01 14:49:36.756: I/System.out(13871): getview 3 null
01-01 14:49:36.776: I/System.out(13871): getview 4 null
mais maintenant son résolu, je sais, je ne suis pas si bon à expliquer mais comme je mis toute ma journée pour comprendre alors j'ai pensé d'autres débutants comme moi peuvent obtenir de l'aide de mon expérience et j'espère maintenant que vous les gens auront un peu de compréhension de ListView cadre comment cela fonctionne, car il est vraiment salissant et délicat afin débutants ont trouvé trop de problèmes de compréhension de l'it
prendre soin, dans le modèle de support, si vous définissez la position dans votre objet de support, vous devriez le définir à chaque fois , par exemple:
@Override
public final View getView(int position, View view, ViewGroup parent) {
Holder holder = null;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) App.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(getContainerView(), parent, false);
holder = getHolder(position, view, parent);
holder.setTag(tag);
view.setTag(holder);
} else {
holder = (Holder) view.getTag();
}
holder.position = position;
draw(holder);
return holder.getView();
}
il s'agit d'un exemple tiré d'une classe abstraite, où
getHolder(position, view, parent);
effectue toutes les opérations de réglage pour le
ImageViews, TextViews, etc..
en utilisant le modèle de support, vous pouvez obtenir ce que vous voulez:
vous pouvez trouver la description de ce modèle ici:
le recyclage de la vue de liste se produit lorsque vous faites défiler vers le bas de l'écran et les éléments de la vue de liste ci-dessus sont cachés . Ils sont réutilisés pour afficher de nouveaux éléments de liste.