了解ViewHolder模式

时间:2015-05-09 14:48:04

标签: android listview recycle

我为ListView创建了一个适配器,它有两种类型的行。 ListView有4行。最后一行有不同的布局,这就是我在getview中使用GetItemViewType方法的原因

我试图了解这种模式是如何运作的。我看了这个: https://www.youtube.com/watch?v=bWsWe9T9HJw以便更好地了解 如何回收利用

我不明白的是:当我在listview中向下滚动时,转换视图 永远是空的。当我再次向上滚动时,convertview不为null并且可以重复使用。

对于列表中的第一项,不应该将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;
    }

2 个答案:

答案 0 :(得分:1)

  

对于列表中的第一项,不应该将convertview设为null吗?

通常不会。

假设ListView中有8行可见。这意味着ListViewgetView() null至少8次调用convertView参数,以填充ListView中的可见空间。

ListView也可以缓存一些额外的行,以便能够快速响应滚动事件,作为缓存。

另外,在您的情况下,为每种视图类型维护了单独的对象池。

如果您的适配器中有足够的东西,最终即使在初始向下滚动期间也会回收。这完全取决于行的大小,适配器从getCount()返回的值等等。

请注意,这与视图持有者模式没有任何关系。

答案 1 :(得分:0)

此方法中传递给您的View是列表中显示的实际View(如果需要您创建一个,则为null。)

例如,如果您的列表足够高以显示6个项目,则它确实需要至少有6个实例可供使用! 然而,滚动时,一个View离开窗口,可以重复用于列表的另一侧。

这对你有意义吗?