Android RecyclerView切换布局(网格/列表)旧viewHolders使用

时间:2016-10-18 10:52:28

标签: android android-recyclerview refresh android-viewholder

问题摘要

我在活动中有一个RecyclerView列表,其中有一个actionBar按钮,用于在LIST和GRID布局之间切换RecyclerView。

将列表视为LIST和GRID时,项目的布局会有所不同。

查看LIST中的项目时,行格式为

|----|
|icon|  Item Name
|----|

在GRID中查看项目时,行格式为

|--------------|
| large icon   |
|              |
|              |
|              |      
|--------------|
    Item Name

因此,我在列表中查看我的列表

|----|
|icon|  Item1
|----|
|----|
|icon|  Item2
|----|
|----|
|icon|  Item3
|----|
|----|
|icon|  Item3
|----|

当我将列表视为GRID时,我看到了

|--------------|    |--------------|
| large icon   |    | large icon   |      
|              |    |              |      
|              |    |              |      
|              |    |              |      
|--------------|    |--------------|
    Item1                Item2
|--------------|    |--------------|
| large icon   |    | large icon   |
|              |    |              |
|              |    |              |
|              |    |              |      
|--------------|    |--------------|
    Item3                Item4

当我使用actionBar按钮将列表视图从LIST切换到GRID或GRID切换到LIST时,某些视图仍会在其他样式的布局中呈现。我相信,在切换之前滚动视线的视图会被回收再利用而不是重新创建。

例如,如果我从GRID转到LIST,我会看到

                    |--------------|
                    | large icon   |      
|----|              |              |      
|icon|  Item1       |              |      
|----|              |              |      
                    |--------------|
                         Item2
|--------------|    |--------------|
| large icon   |    | large icon   |
|              |    |              |
|              |    |              |
|              |    |              |      
|--------------|    |--------------|
    Item3                Item4

背景代码信息

我有2个布局管理器;每个布局样式一个

private RecyclerView.LayoutManager linearLayoutManager;
private RecyclerView.LayoutManager gridLayoutManager;

在适配器中我存储我是否将列表显示为网格或列表

enum ListViewEnum{
    LIST,
    GRID
}

ListViewEnum listViewStyle = ListViewEnum.LIST;

public ListViewEnum getListStyle() {
    return listViewStyle;
}

列表中项目的布局取决于列表是作为列表还是网格呈现。

ViewHolderList
ViewHolderGrid

创建视图持有者时,我将视图持有者的类型基于适配器列表视图样式

protected RecyclerView.ViewHolder getItemViewHolder(ViewGroup parent){
    if (listViewStyle == ListViewEnum.LIST){
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_row, parent, false);
        return new ViewHolderList(itemView, ....);
    } else {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_row, parent, false);
        return new ViewHolderGrid(itemView, ....);
    }
}

当用户点击actionBar按钮时,我切换适配器的值

getListAdapter().setListViewMode(ListViewMode.LIST);

然后刷新

listView.setLayoutManager(getListAdapter().getListStyle() == ListViewEnum.LIST ? linearLayoutManager : gridLayoutManager);
getListAdapter().notifyDataSetChanged();
listView.invalidateItemDecorations();
invalidateOptionsMenu();

我知道我正在刷新列表适配器,但它不会放弃recycleViews。调试显示,在点击切换按钮时,我看到只有" onBindViewHolder"对于某些职位(回收的职位)和" onCreateViewHolder"和" onBindViewHolder"(对于新的)因此表明旧的视图持有者正在被回收。

如何刷新列表以便不会从错误的列表样式重新使用ViewHolders?

2 个答案:

答案 0 :(得分:2)

来自@Abbas的评论是正确的,getItemViewType()可能是你最好的选择。根据您的数据,您可以使用一个持有者,但如果数据项不同,您可能必须创建两个。使用适配器内的getItemViewType()调用来确定要显示的内容。您将需要将标志从活动或回调传递到适配器中以获取类型。

public static final int SMALL_VIEW = 0;
public static final int LARGE_VIEW = 1;
private int mType = 0;

@Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v;
        RecyclerView.ViewHolder viewHolder = null;

        // Create the Holders depending on the type, the view type
        // will come from the getItemViewType() call.

        switch ( viewType ) {
            case SMALL_VIEW:
                v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_row, parent, false);
                viewHolder = new ViewHolderList(mContext, v);
                break;

            case LARGE_VIEW:
                v = LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_row, parent, false);

              viewHolder = new ViewHolderGrid(mContext, v);
            default:

        }
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        // This switch may not be necessary if you are using 
        // the same holder for both items.
        switch ( getItemViewType(position) ) {
            case SMALL_ITEM:
                ViewHolderList list = (ViewHolderList)holder;
                list.setData(mData.get(position));
                break;
            case LARGE_ITEM:
                ViewHolderGrid grid = (ViewHolderGrid)holder;
                grid.setData(mData.get(position));
        }
    }

    @Override
    public int getItemViewType(int position) {
        // Normally you identify the data type at position and
        // switch the view, for your application you can switch
        // for all.
        return mType;
    }

    public void setViewType(int type) {
       mType = type;
    }

答案 1 :(得分:1)

由于RecyclerViews内存管理,RecyclerView尝试重用视图以更快地滚动。我认为使用两个适配器实例而不是一个,并使用选定的适配器重新填充回收器可能有所帮助。

相关问题