避免在android适配器的getView()方法中实例化和添加子视图

时间:2014-06-13 19:15:47

标签: android listview android-listview

方案

我正在尝试创建类似于Google Play商店中的精选页面的内容。但不是为类别显示三个项目,而是允许它以两列staggered grid view方式显示任意数量的项目。

因此,每个列表项都有一个标题,其标题和描述后跟自定义视图(让我们调用此SVG,如在交错视图组中),以交错的网格视图方式显示一些子视图。

我有一个名为FeaturedItems的类,用于保存特色列表中一行的数据。这是一个摘录:

public class FeaturedItems {

private String mName;
private String mDescription;
private ArrayList<Object> mList;

public FeaturedItems(String name, String description, Object... items) {
    mName = name;
    mDescription = description;
    mList = new ArrayList<Object>();
    for (int i = 0; i < items.length; i++) {
        mList.add(items[i]);

    }
}

public int getItemCount() {
    return mList.size();
}

public Object getItem(int position) {
    return mList.get(position);
}

public String getFeatureName() {
    return mName;
}

public String getFeatureDescription() {
    return mDescription;
}

}

FeaturedListAdapter将数据与适配器的getView()方法中的视图绑定在一起。 getView()方法如下:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    FeaturedItems items = getItem(position);

    if (convertView == null) {
        LayoutInflater infalInflater = (LayoutInflater) this.mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = infalInflater.inflate(mResource, null);

        holder = new ViewHolder();
        holder.title = (TextView) convertView.findViewById(R.id.list_item_shop_featured_title);
        holder.description = (TextView) convertView.findViewById(R.id.list_item_shop_featured_description);
        holder.svg = (StaggeredViewGroup) convertView.findViewById(R.id.list_item_shop_featured_staggered_view);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    holder.title.setText(items.getFeatureName());
    holder.description.setText(items.getFeatureDescription());

    // HELP NEEDED HERE
    // THE FOLLOWING PART IS VERY INEFFICIENT
    holder.svg.removeAllViews();

    for (int i = 0; i < items.getItemCount(); i++) {
            FeaturedItem item = new FeaturedItem(mContext, items.getItem(i));
            item.setOnShopActionsListener((ShopActions) mContext);
            holder.svg.addView(item);
    }

    return convertView;
}

问题

getView()方法中,每次返回视图时,它都会删除SVG中的所有子视图,并实例化名为FeaturedItem的新视图,然后将其添加到SVG中。即使第一行中的特定行中的SVG已填充,当用户从底部向后滚动时,getView()方法将删除SVG中的所有子视图并实例化要填充的新视图用。

这里效率低下非常明显,列表视图动画在经常滚动时会跳过帧。

我无法在此重复使用convertView,因为它会在StaggeredViewGroup中显示错误的特色项目。因此,我必须从StaggeredViewGroup中删除所有子项并实例化并添加与当前位置相关的视图。

问题

有解决这个问题的方法吗?或者是否有一些替代方法来创建类似于Google Play商店特色页面的页面,但每行都有不同数量的特色商品,因此具有独特的高度?

1 个答案:

答案 0 :(得分:2)

应该有一种简单的方法来改进此解决方案。只需重用已经存在的svg子项,如果它们不够就添加新的子项,然后删除任何剩余的子项。

例如(在半伪代码中,方法名称可能不准确):

for (int i = 0; i < items.getItemCount(); i++)
{
    if (i < svg.getChildCount())
    {
        FeaturedItem item = i.getChildAt(i);

        // This item might've been set to invisible the previous time
        // (see below). Ensure it's visible.
        item.setVisibility(View.VISIBLE);

        // reuse the featuredItem view here, e.g.
        item.setItem(items.getItem(i));
    }
    else
    {
        // Add one more item
        FeaturedItem item = new FeaturedItem(mContext, items.getItem(i));
        ...
        holder.svg.addView(item);
    }
}

// hide surplus item views.
for (int i = items.getItemCount(); i < svg.getChildCount(); i++)
    svg.getChildAt(i).setVisibility(View.GONE);

/** 
  as an alternative to this last part, you could delete these surplus views
  instead of hiding them -- but it's probably wasteful, since they may need 
  to be recreated later

while (svg.getChildCount() > items.getItemCount())
    svg.removeChildView(svg.getChildCount() - 1);
**/