了解 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 中退出,并且可以在列表的另一侧重复使用。

你觉得这有意义吗?