Recyclerview 回收的viewholders合并

Recyclerview Recycled viewholders merging

我有回收站观点。我有很多针对不同内容类型的视图持有者。

我这样创建我的支架:

  /**
     * Create instance of
     * compatible viewholder
     *
     * @param viewType
     * @param parent
     * @return
     */
    private AbstractHolder createAbstractHolder(int viewType, ViewGroup parent) {
        AbstractHolder holder = null;

        switch (viewType) {
            case VersyConstants.HOLDER_TYPE_1:
                holder = ViewHolder_Var1.create(parent, mUserHomeFragment, mUserStreamFragment);

                break;

            case VersyConstants.HOLDER_TYPE_2:
                holder = ViewHolder_Var2.create(parent, mUserHomeFragment, mUserStreamFragment);
                break;

            case VersyConstants.HOLDER_TYPE_3:
                holder = ViewHolder_Var3.create(parent, mUserHomeFragment, mUserStreamFragment);
                L.i(getClass().getSimpleName(), "HOLDER 3");
                break;

            case VersyConstants.HOLDER_TYPE_4:
                holder = ViewHolder_Var4.create(parent, mUserHomeFragment, mUserStreamFragment);
                L.i(getClass().getSimpleName(), "HOLDER 4");
                break;

            case VersyConstants.HOLDER_TYPE_5:
                holder = ViewHolder_Var5.create(parent, mUserHomeFragment, mUserStreamFragment);
                L.i(getClass().getSimpleName(), "HOLDER 5");
                break;

            case VersyConstants.HOLDER_TYPE_6:
                holder = ViewHolder_Var6.create(parent,  mUserHomeFragment, mUserStreamFragment);
                L.i(getClass().getSimpleName(), "HOLDER 6");
                break;

            case VersyConstants.HOLDER_TYPE_7:
                holder = ViewHolder_Var7.create(parent, mUserHomeFragment, mUserStreamFragment);
                L.i(getClass().getSimpleName(), "HOLDER 7");
                break;

            case VersyConstants.HOLDER_TYPE_8:
                holder = ViewHolder_Var8.create(parent, mUserHomeFragment, mUserStreamFragment);
                L.i(getClass().getSimpleName(), "HOLDER 8");
                break;

            case VersyConstants.HOLDER_TYPE_9:
                holder = ViewHolder_Var9.create(parent, mUserHomeFragment, mUserStreamFragment);
                break;

            case VersyConstants.HOLDER_TYPE_10:
                holder = ViewHolder_Var10.create(parent, mThumbnailViewToLoaderMap, mUserHomeFragment, mUserStreamFragment);
        }
        return holder;
    }

问题是当我向下滚动回收站视图时遇到的问题,例如,当我向上滚动到项目编号时,为第一项和第五项创建了视图持有者 3。 1,它有第 5 项的回收视图持有者,我知道这是回收视图的想法。

如果相关数据进入 JSON,我在 viewholders 中是 hiding/showing 文本视图。如果存在,我将显示散列标签,因此在下面的第一项中:

然后当我向下滚动到第 5 个带有标签的项目时(如下):

然后当我向上滚动到第一个项目时,标签会在不应该添加的时候添加,因为没有与此对象关联的标签数据(见下文):

我已经调试过,对象数据没有混淆,没有通过代码添加标签,这取决于recyclerview回收,这两个项目有相同的view holder(view holder 3)。有什么办法可以防止这种情况吗?

下面是填充标签的方法。根据列表大小,我将文本视图的可见性设置为可见并填充:

 protected void populateTags(List<String>tags, TextView[] array){
        for(int i=0;i<tags.size(); i++){
            array[i].setText(tags.get(i));
            array[i].setVisibility(View.VISIBLE);
        }
    }

上面我这样称呼List<String> tagsList = feedContent.getTags(); if(tagsList.size>0)populateTags(tagsList, tagsArray); 这不仅仅发生在第 1 项和第 5 项中,它取决于哪些视图被重用。如果有一个视图重用于已经显示标签的视图,则添加来自重用视图的标签。非常糟糕

所以我在 SO 上找到了这个问题 。与上述问题相同,但建议的答案无效。我注意到 "This usually happens when you have something like "if (field != null) holder.setField(field)", 没有 else。支架是回收的,这意味着它在那里会有值,所以你需要清理或更换每一个值,如果它为 null,你应该 nullit,如果不是,你应该写它,总是。已经晚了,但是,作为对其他人的回答。”在评论中。因此,我将调用从 if(tagsList.size>0)populateTags(tagsList, tagsArray); 更改为 populateTags(tagsList, tagsArray);,因为我没有 else 并且该逻辑在方法中。

就是这样..希望对其他人有所帮助

基本上,RecyclerView 就是回收。它会重复使用容器,但 不会重置它们!

这意味着每次用数据填充 ViewHolder 时,都需要添加新数据并删除旧数据(或隐藏一些视图)。如果你不这样做,你最终会得到来自先前膨胀对象的数据:-(

编辑: 所以,如果你的充气代码中有这样的东西

if(item.getTagsCount() > 0)
    tags.setVisibility(View.VISIBLE);

你需要更新成这样

if(item.getTagsCount() > 0)
    tags.setVisibility(View.VISIBLE);
else 
    tags.setVisibility(View.GONE);

if(item.getTagsCount() > 0)
    tags.setVisibility(View.VISIBLE);
else if(item.getTagsCount() == 0)
    tags.setVisibility(View.GONE);

当然,这只是一个示例性条件。请记住,如果您将一些数据放入 ViewHolder,您还需要防范没有数据可放入其中的情况。