问题
I created an adapter for a ListView which has two types of rows. The ListView has 4 rows. The last row has a different layout, that's why i use the GetItemViewType method in getview
I'm trying to understand how the pattern works. I watched this: https://www.youtube.com/watch?v=bWsWe9T9HJw to get a better understanding of how recycling works
What i don't understand is: when i scroll down in my listview, the convertview is always null. When i scroll back up again, the convertview is not null and is reusable.
Shouldn't convertview be null only for the first item in the list? i don't get why it is null for each new item?
public override View GetView (int position, View convertView, ViewGroup parent)
{
BaseBundelVO bundle = _bundles [position];
DSBundleListItem bundleHolder = null;
DSBundleArchiveItem archiveHolder = null;
int type = GetItemViewType(position);
if (convertView == null)
{
bundleHolder = new DSBundleListItem (_activity);
archiveHolder = new DSBundleArchiveItem (_activity);
switch (type)
{
case 0:
convertView = _activity.LayoutInflater.Inflate (Resource.Layout.dsBundleListItem, null);
bundleHolder.IconIv = convertView.FindViewById<ImageView> (Resource.Id.iconIv);
bundleHolder.CoverIv = convertView.FindViewById<ImageView> (Resource.Id.coverIv);
bundleHolder.CoverTitleTv = convertView.FindViewById<TextView> (Resource.Id.coverTitleTv);
bundleHolder.CoverSubTitleTv = convertView.FindViewById<TextView> (Resource.Id.coverSubTitleTv);
bundleHolder.BundleProgress = convertView.FindViewById<ProgressBar> (Resource.Id.bundleProgress);
convertView.Tag = bundleHolder;
break;
case 1:
convertView = _activity.LayoutInflater.Inflate (Resource.Layout.dsBundleArchiveItem, null);
archiveHolder.ArchiveTitleTv = convertView.FindViewById<TextView> (Resource.Id.archiveTitleTv);
archiveHolder.ArchiveSubTitleTv = convertView.FindViewById<TextView> (Resource.Id.archiveSubTitleTv);
convertView.Tag = archiveHolder;
break;
}
}
else
{
switch (type)
{
case 0:
bundleHolder = (DSBundleListItem)convertView.Tag;
Console.WriteLine (bundleHolder.IsDisposed ());
bundleHolder.RemoveImageLoaderCallBack ();
break;
case 1:
archiveHolder = (DSBundleArchiveItem)convertView.Tag;
Console.WriteLine (archiveHolder.IsDisposed ());
archiveHolder.RemoveImageLoaderCallBack ();
break;
}
}
switch (type)
{
case 0:
bundleHolder.CoverTitleTv.Text = bundle.Title;
bundleHolder.CoverSubTitleTv.Text = bundle.SubTitle;
bundleHolder.LoadImage(bundle.CoverImageLocation,bundle.Icon);
break;
case 1:
archiveHolder.ArchiveTitleTv.Text = "Archief";
archiveHolder.ArchiveSubTitleTv.Text = "Bekijk onze eerder verschenen publicaties";
break;
}
return convertView;
}
回答1:
Shouldn't convertview be null only for the first item in the list?
Not usually.
Let's suppose that that 8 rows are visible in the ListView
. That means the ListView
will call getView()
at least 8 times with null
for the convertView
parameter, to populate the visible space in the ListView
.
ListView
may also cache a few additional rows, to be able to rapidly respond to scrolling events, as a cache.
Plus, in your case, there are separate object pools maintained for each view type.
If your adapter has enough stuff in it, though, eventually you will recycle even during the initial scroll down. It all depends on the size of the rows, the values that the adapter returns from getCount()
, etc.
And note that this has nothing really to do with the view holder pattern.
回答2:
The View
that is passed to you in this method is the actual View
that is displayed in the list (or null
if it needs you to create one).
If your list is tall enough to show 6 items, for instance, it does need to have at least 6 instances at its disposal!
When you scroll however, one View
gets out of the window, and can be reused for the other side of the list.
Does that make sense to you?
来源:https://stackoverflow.com/questions/30141323/understanding-the-viewholder-pattern