RecyclerView:如何清除缓存/回收的视图?

时间:2015-01-14 20:05:19

标签: android android-recyclerview recycler-adapter

我使用RecyclerView显示列表布局的项目列表。我从列表布局切换到网格布局,在网格布局中仅显示所有数据的子集。此开关使用与列表布局呈现时不同的布局XML。

所有这些都很有效,除了当我滚动,回收(缓存?)列表布局视图填充网格,与适当的网格布局视图项混合。换句话说,我不是在RecyclerView中为每个项目的布局使用layout_grid.xml,而是使用layout_list.xml布局获取项目,但是采用网格格式。

这告诉我LayoutManager工作正常,从列表切换到网格布局。但并非所有项目视图项都使用网格xml布局重新创建,而是使用回收列表布局视图。

我尝试RecyclerView.removeAllViews()RecyclerView.removeAllViewInLayout()RecyclerView.swapAdapter()(强制适配器重新加载),但都无济于事。

更新

如果我在列表中向下滚动两个位置,然后从列表切换到网格,前两个位置不会通过onCreateViewHolder(),而是直接到onBindViewHolder(),因此不会强制使用网格布局xml 。相反,前两个位置项目被回收(我认为)并以列表布局格式显示。

8 个答案:

答案 0 :(得分:21)

使用

recyclerView.getRecycledViewPool().clear();

答案 1 :(得分:8)

我遇到了同样的问题。 Mann提出的解决方案效果很好。另一种选择是将RecyclerView的RecycledViewPool设置为新实例。这对我也有用。

recyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool());

但我认为重写getItemViewType()是更清洁的解决方案。

答案 2 :(得分:6)

好的,我明白了。你使用两种布局?有一种方法可以返回列表/网格元素(id / position)的viewtype。您也正确地实现了此方法,即适配器可以为新视图回收正确的布局。 你明白我的意思吗? :)

答案 3 :(得分:6)

听起来接受的答案是适合您案例的答案,返回不同的viewType可能就是您需要做的事情。

如果有人确实需要找到一种方法来清除缓存的视图持有者并最终进入此主题,那么我发现这是有用的。

您需要致电setLayoutManager(null)setAdapter(null)。如果您想保留适配器,可以执行adapter = getAdapter(); setAdapter(null); setAdapter(adapter);

之类的操作

答案 4 :(得分:4)

这里的关键是覆盖getItemViewType(int position)并设置它以便我可以检查我正在处理该位置的视图类型(列表或网格),然后为该位置设置适当的视图处理onbindViewHolder()。下面,viewFormat只是一个int,当用户点击菜单按钮更改格式时,我将其设置为列表或网格。

@Override
    public int getItemViewType(int position) {
        if (listData.size() == 0) {
            return EMPTY_VIEW;
        } else if (viewFormat == Constants.LIST_FORMATTED) {
            return Constants.LIST_FORMATTED;
        } else if (viewFormat == Constants.GRID_CONDITION) {
            return Constants.GRID_CONDITION;
        }
        return super.getItemViewType(position);
    }

在我的原始帖子上发表评论的用户让我意识到了这一点,但不幸的是,这些评论已被删除。我感谢那位用户指出了我正确的方向。

答案 5 :(得分:0)

Recyclerview具有视图缓存以及回收视图池(视图持有者池)。

缓存是视图(具有填充数据的视图)。当LayoutManager告诉recyclerview该视图不再可见且需要时,recyclelerview会检查该视图是否仍然对特定位置有效,如果该视图有效则将其添加到缓存中,因此当下次LM要求查看该位置时,它将返回来自缓存原样。

那么什么是回收视图池?当从缓存中删除视图或没有更多有效视图时,将清除与这些视图相关的数据,并且只有视图持有者对象保留在池中。根据itemType,池可以具有不同项类型的视图持有者。

现在,在您的情况下,您的观点对于该特定位置无效,因为您想要显示完全不同的视图。因此,您的适配器应该告诉recyclerview所有视图都是无效的。唯一的方法是对所有项目使用notifyDataSetChanged。 Recyclerview将从缓存中删除视图并将其添加到recyler视图池。所以现在,当LM请求查看时,将返回循环视图(根据itemType)或新创建的视图,并且适配器将数据绑定到这些视图。

答案 6 :(得分:0)

就这样做 简单!!

adapter.notifyItemRangeRemoved(0,adapter.getItemCount());

  adapter.notifyItemRangeRemoved(0,adapter.getItemCount());
                   for (int i = 0; i < array.length(); i++) {
                        JSONObject object = array.getJSONObject(i);
                         ////
                        data_List.add(data);
                    }

答案 7 :(得分:0)

final int targetCacheSize = 2;
    recyclerView.setItemViewCacheSize(Integer.MIN_VALUE);
    recyclerView.getRecycledViewPool().clear();
    recyclerView.setItemViewCacheSize(targetCacheSize);