代码之家  ›  专栏  ›  技术社区  ›  LordSuricato

RecyclerView上viewholder中的动态项目

  •  2
  • LordSuricato  · 技术社区  · 7 年前

    如果我们有N个类别(根据REST API在1到100之间),每个类别都有X个项目(根据类别在1到50之间),那么进行类别回收视图的最佳方式是什么?

    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 回复  |  直到 7 年前
        1
  •  2
  •   Ben P.    7 年前

    为了回答你的问题,我要回到 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() 每一次

    通过使用 convertView 参数,第2个问题由“视图保持器模式”求解。当谷歌开发团队创建 RecyclerView 要替换的API 列表视图 ,他们使“视图持有者”成为一等公民,现在每个人都与 RecyclerView.ViewHolder 默认情况下为。

    重要的是要记住,避免重复视图膨胀和重复视图查找的性能增益是 太有价值了 谷歌将其融入新系统。

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

    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() 上述实施已完成。为类别中的每个项目扩展新视图,并调用 掌握它的 ImageView 这将是昂贵的,尤其是当用户抛出列表时。

    要解决性能问题,只需对“内部”内容列表应用与“外部”内容相同的逻辑:使用 回收视图 对于项目(每个内部 ViewHolder 对于类别)。

    https://gist.github.com/zizibaloob/2eb64f63ba8d1468100a69997d525a54