RecyclerView上的viewholder中的动态项目

时间:2017-11-13 01:02:01

标签: android android-recyclerview android-viewholder

如果我们有N个类别(根据REST API在1到100之间)并且每个类别都有X个项目(1到50之间,具体取决于类别),那么做一个类别RecyclerView的最佳方法是什么?

Schematic image.

要添加这样做,我将在方法“onBindViewHolder”中为类别的每个项目项添加卡片视图,如下所示:

    @Override
public void onBindViewHolder(MoviesViewHolder holder, int i) {
    holder.title.setText(items.get(i).getTitle());

     // I add a CardView (item_category.xml) for each item in the list

    for (ObjectShort object: items.get(i).getObjects()) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.item_category, holder.linearCategories, false);
        ImageView img = (ImageView) view.findViewById(R.id.iv_wallpaper);
        imageLoader.load(img, object.getImg().getPoster().getThumbnail());
        holder.linearCategories.addView(view);
    }

}

当它被回收时,我删除了“onViewRecycled”中的ITEMS元素,因为如果我在进行垂直滚动和重新加载类别时不这样做,则会再次添加项目重复:

    @Override
public void onViewRecycled(MoviesViewHolder holder) {
    // delete all items 
    holder.linearCategories.removeAllViews();
}

有没有更好的方法呢?这是无效的,滚动非常慢

感谢所有

1 个答案:

答案 0 :(得分:2)

要回答你的问题,我将回到ListView的旧时代。让我们想象一下,我有一个简单的列表,其中每一行只是一个标题和一个图像。支持该列表的getView()真正天真的实现可能如下所示:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    View view = inflater.inflate(R.layout.itemview, parent, false);

    TextView title = view.findViewById(R.id.title);
    title.setText("hello world");

    ImageView image = view.findViewById(R.id.image);
    image.setImageResource(R.drawable.my_image);

    return view;
}

此实施中存在两个主要的性能问题来源:

  1. 我们每次都在夸大新视图

  2. 我们每次都在致电findViewById()

  3. 通过使用convertView参数解决了数字1,并且通过名为"视图持有者模式"的东西解决了数字2。当Google开发团队创建了RecyclerView API来替换ListView时,他们会制作"查看持有者"一流的公民,现在每个人都默认使用RecyclerView.ViewHolder

    重要的是要记住,避免重复查看通知和重复查看查找的性能提升非常有价值,Google将它们烘焙到新系统中。

    现在让我们看看你的代码......

    public void onBindViewHolder(MoviesViewHolder holder, int i) {
        ...
        for (ObjectShort object: items.get(i).getObjects()) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View view = inflater.inflate(R.layout.item_category, holder.linearCategories, false);
            ImageView img = (ImageView) view.findViewById(R.id.iv_wallpaper);
            imageLoader.load(img, object.getImg().getPoster().getThumbnail());
            holder.linearCategories.addView(view);
        }
    }
    

    绑定方法中的这个for循环具有与我上面的天真getView()实现相同的所有问题。为类别中的每个项目膨胀新视图,并调用findViewById()来获取其ImageView的费用将会非常昂贵,尤其是当用户将列表移动时。

    要解决您的性能问题,只需将相同的逻辑应用于您的内部"你所拥有的内容列表"外部"内容:对项目使用RecyclerView(每个ViewHolder内的类别)。

    这是一个非常简单的示例应用,它说明了我的解决方案:https://gist.github.com/zizibaloob/2eb64f63ba8d1468100a69997d525a54