了解 ViewHolder 模式
Understanding the ViewHolder pattern
我为 ListView 创建了一个适配器,它有两种类型的行。 ListView 有 4 行。最后一行有不同的布局,这就是为什么我在 getview
中使用 GetItemViewType 方法
我正在尝试了解该模式的工作原理。我看了这个:
https://www.youtube.com/watch?v=bWsWe9T9HJw 更好地了解
回收工作原理
我不明白的是:当我在列表视图中向下滚动时,convertview
始终为空。当我再次向上滚动时,convertview 不为空并且可以重复使用。
convertview 不应该只对列表中的第一项为 null 吗?我不明白为什么
每个新项目都为空?
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;
}
Shouldn't convertview be null only for the first item in the list?
通常不会。
假设 ListView
中有 8 行可见。这意味着 ListView
将调用 getView()
至少 8 次 null
作为 convertView
参数,以填充 ListView
中可见的 space .
ListView
还可以缓存一些额外的行,以便能够快速响应滚动事件,作为缓存。
此外,在您的情况下,每个视图类型都有单独的对象池。
不过,如果您的适配器中有足够的东西,即使在初始向下滚动期间,您最终也会回收。这完全取决于行的大小、适配器 returns 来自 getCount()
的值等
请注意,这与视图持有者模式无关。
在此方法中传递给您的 View
是列表中显示的实际 View
(如果需要您创建一个,则为 null
)。
例如,如果您的列表足够高以显示 6 个项目,则它确实需要至少有 6 个实例可供使用!
但是,当您滚动时,一个 View
从 window 中退出,并且可以在列表的另一侧重复使用。
你觉得这有意义吗?
我为 ListView 创建了一个适配器,它有两种类型的行。 ListView 有 4 行。最后一行有不同的布局,这就是为什么我在 getview
中使用 GetItemViewType 方法我正在尝试了解该模式的工作原理。我看了这个: https://www.youtube.com/watch?v=bWsWe9T9HJw 更好地了解 回收工作原理
我不明白的是:当我在列表视图中向下滚动时,convertview 始终为空。当我再次向上滚动时,convertview 不为空并且可以重复使用。
convertview 不应该只对列表中的第一项为 null 吗?我不明白为什么 每个新项目都为空?
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;
}
Shouldn't convertview be null only for the first item in the list?
通常不会。
假设 ListView
中有 8 行可见。这意味着 ListView
将调用 getView()
至少 8 次 null
作为 convertView
参数,以填充 ListView
中可见的 space .
ListView
还可以缓存一些额外的行,以便能够快速响应滚动事件,作为缓存。
此外,在您的情况下,每个视图类型都有单独的对象池。
不过,如果您的适配器中有足够的东西,即使在初始向下滚动期间,您最终也会回收。这完全取决于行的大小、适配器 returns 来自 getCount()
的值等
请注意,这与视图持有者模式无关。
在此方法中传递给您的 View
是列表中显示的实际 View
(如果需要您创建一个,则为 null
)。
例如,如果您的列表足够高以显示 6 个项目,则它确实需要至少有 6 个实例可供使用!
但是,当您滚动时,一个 View
从 window 中退出,并且可以在列表的另一侧重复使用。
你觉得这有意义吗?