什么是使用RecyclerView.Adapter的SortedList <t>?

时间:2015-04-22 10:54:03

标签: android android-appcompat android-recyclerview sortedlist

昨天发布了

Android支持库22.1 。 v4支持库和v7中添加了许多新功能,其中android.support.v7.util.SortedList<T>引起了我的注意。

据说,SortedList是一个新的数据结构,与RecyclerView.Adapter一起使用,维护RecyclerView提供的项目添加/删除/移动/更改的动画。它听起来像List<T>中的ListView,但看起来更先进,更强大。

那么,SortedList<T>List<T>之间有什么区别?我怎么能有效地使用它?如果是SortedList<T>List<T>的执行情况是什么?有人可以发一些样品吗?

任何提示或代码将不胜感激。提前谢谢。

3 个答案:

答案 0 :(得分:94)

SortedList通过Callback处理与Recycler适配器的通信。

SortedListList之间的一个区别在于下面示例中的addAll辅助方法。

public void addAll(List<Page> items) {
        mPages.beginBatchedUpdates();
        for (Page item : items) {
            mPages.add(item);
        }
        mPages.endBatchedUpdates();
    }
  1. 保留最后添加的项目
  2. 假设我填充了我的回收站列表时,我立即加载了10个缓存项目。同时,我在网络中查询相同的10个项目,因为自从我缓存它们以来它们可能已经发生了变化。我可以调用相同的addAll方法,SortedList将使用fetchedItems替换cachedItems(始终保留最后添加的项目)。

    // After creating adapter
    myAdapter.addAll(cachedItems)
    // Network callback
    myAdapter.addAll(fetchedItems)
    

    在常规List中,我会复制所有项目(列表大小为20)。 SortedList使用回调areItemsTheSame替换相同的项目。

    1. 知道何时更新视图
    2. 添加fetchedItems后,只有onChange的一个或多个标题发生更改时才会调用Page。您可以自定义Callback的SortedListareContentsTheSame查找的内容。

      1. 其表现
      2.   

        如果要向SortedList添加多个项目,BatchedCallback调用会将单个onInserted(index,1)调用转换为一个onInserted(index,N),前提是将项目添加到连续索引中。此更改可以帮助RecyclerView更轻松地解决更改。

        样品

        您可以在适配器上为SortedList添加一个getter,但我决定在我的适配器中添加帮助方法。

        适配器类:

          public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
            private SortedList<Page> mPages;
        
            public MyAdapter() {
                mPages = new SortedList<Page>(Page.class, new SortedList.Callback<Page>() {
                    @Override
                    public int compare(Page o1, Page o2) {
                        return o1.getTitle().compareTo(o2.getTitle());
                    }
        
                    @Override
                    public void onInserted(int position, int count) {
                        notifyItemRangeInserted(position, count);
                    }
        
                    @Override
                    public void onRemoved(int position, int count) {
                        notifyItemRangeRemoved(position, count);
                    }
        
                    @Override
                    public void onMoved(int fromPosition, int toPosition) {
                        notifyItemMoved(fromPosition, toPosition);
                    }
        
                    @Override
                    public void onChanged(int position, int count) {
                        notifyItemRangeChanged(position, count);
                    }
        
                    @Override
                    public boolean areContentsTheSame(Page oldItem, Page newItem) {
                        // return whether the items' visual representations are the same or not.
                        return oldItem.getTitle().equals(newItem.getTitle());
                    }
        
                    @Override
                    public boolean areItemsTheSame(Page item1, Page item2) {
                        return item1.getId() == item2.getId();
                    }
                });
        
            }
        
            @Override
            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                View view = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.viewholder_page, parent, false);
                return new PageViewHolder(view);
            }
        
            @Override
            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
                PageViewHolder pageViewHolder = (PageViewHolder) holder;
                Page page = mPages.get(position);
                pageViewHolder.textView.setText(page.getTitle());
            }
        
            @Override
            public int getItemCount() {
                return mPages.size();
            }
        
            // region PageList Helpers
            public Page get(int position) {
                return mPages.get(position);
            }
        
            public int add(Page item) {
                return mPages.add(item);
            }
        
            public int indexOf(Page item) {
                return mPages.indexOf(item);
            }
        
            public void updateItemAt(int index, Page item) {
                mPages.updateItemAt(index, item);
            }
        
            public void addAll(List<Page> items) {
                mPages.beginBatchedUpdates();
                for (Page item : items) {
                    mPages.add(item);
                }
                mPages.endBatchedUpdates();
            }
        
            public void addAll(Page[] items) {
                addAll(Arrays.asList(items));
            }
        
            public boolean remove(Page item) {
                return mPages.remove(item);
            }
        
            public Page removeItemAt(int index) {
                return mPages.removeItemAt(index);
            }
        
            public void clear() {
               mPages.beginBatchedUpdates();
               //remove items at end, to avoid unnecessary array shifting
               while (mPages.size() > 0) {
                  mPages.removeItemAt(mPages.size() - 1);
               }
               mPages.endBatchedUpdates();
            }
        }
        

        Page class:

        public class Page {
            private String title;
            private long id;
        
            public String getTitle() {
                return title;
            }
        
            public void setTitle(String title) {
                this.title = title;
            }
        
            public long getId() {
                return id;
            }
        
            public void setId(long id) {
                this.id = id;
            }
        }
        

        Viewholder xml:

        <?xml version="1.0" encoding="utf-8"?>
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
        
            <TextView
                android:id="@+id/text_view"
                style="@style/TextStyle.Primary.SingleLine"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        
        </LinearLayout>
        

        观看者类:

        public class PageViewHolder extends RecyclerView.ViewHolder {
            public TextView textView;
        
        
            public PageViewHolder(View itemView) {
                super(itemView);
                textView = (TextView)item.findViewById(R.id.text_view);
            }
        }
        

答案 1 :(得分:14)

SortedList位于v7 support library

  

SortedList实施,可以保持项目的顺序   通知列表中的更改,以便它可以绑定到a   RecyclerView.Adapter

     

它使用compare(Object, Object)方法保存订购商品   使用二进制搜索来检索项目。如果你的排序标准   项目可能会更改,请确保在编辑时调用适当的方法   它们是为了避免数据不一致。

     

您可以通过控制项目的顺序和更改通知   SortedList.Callback参数。

以下是使用SortedList的示例,我认为这是您想要的,看看它并享受!

public class SortedListActivity extends ActionBarActivity {
    private RecyclerView mRecyclerView;
    private LinearLayoutManager mLinearLayoutManager;
    private SortedListAdapter mAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.sorted_list_activity);
        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mRecyclerView.setHasFixedSize(true);
        mLinearLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLinearLayoutManager);
        mAdapter = new SortedListAdapter(getLayoutInflater(),
                new Item("buy milk"), new Item("wash the car"),
                new Item("wash the dishes"));
        mRecyclerView.setAdapter(mAdapter);
        mRecyclerView.setHasFixedSize(true);
        final EditText newItemTextView = (EditText) findViewById(R.id.new_item_text_view);
        newItemTextView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
                if (id == EditorInfo.IME_ACTION_DONE &&
                        (keyEvent == null || keyEvent.getAction() == KeyEvent.ACTION_DOWN)) {
                    final String text = textView.getText().toString().trim();
                    if (text.length() > 0) {
                        mAdapter.addItem(new Item(text));
                    }
                    textView.setText("");
                    return true;
                }
                return false;
            }
        });
    }

    private static class SortedListAdapter extends RecyclerView.Adapter<TodoViewHolder> {
        SortedList<Item> mData;
        final LayoutInflater mLayoutInflater;
        public SortedListAdapter(LayoutInflater layoutInflater, Item... items) {
            mLayoutInflater = layoutInflater;
            mData = new SortedList<Item>(Item.class, new SortedListAdapterCallback<Item>(this) {
                @Override
                public int compare(Item t0, Item t1) {
                    if (t0.mIsDone != t1.mIsDone) {
                        return t0.mIsDone ? 1 : -1;
                    }
                    int txtComp = t0.mText.compareTo(t1.mText);
                    if (txtComp != 0) {
                        return txtComp;
                    }
                    if (t0.id < t1.id) {
                        return -1;
                    } else if (t0.id > t1.id) {
                        return 1;
                    }
                    return 0;
                }

                @Override
                public boolean areContentsTheSame(Item oldItem,
                        Item newItem) {
                    return oldItem.mText.equals(newItem.mText);
                }

                @Override
                public boolean areItemsTheSame(Item item1, Item item2) {
                    return item1.id == item2.id;
                }
            });
            for (Item item : items) {
                mData.add(item);
            }
        }

        public void addItem(Item item) {
            mData.add(item);
        }

        @Override
        public TodoViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
            return new TodoViewHolder (
                    mLayoutInflater.inflate(R.layout.sorted_list_item_view, parent, false)) {
                @Override
                void onDoneChanged(boolean isDone) {
                    int adapterPosition = getAdapterPosition();
                    if (adapterPosition == RecyclerView.NO_POSITION) {
                        return;
                    }
                    mBoundItem.mIsDone = isDone;
                    mData.recalculatePositionOfItemAt(adapterPosition);
                }
            };
        }

        @Override
        public void onBindViewHolder(TodoViewHolder holder, int position) {
            holder.bindTo(mData.get(position));
        }

        @Override
        public int getItemCount() {
            return mData.size();
        }
    }

    abstract private static class TodoViewHolder extends RecyclerView.ViewHolder {
        final CheckBox mCheckBox;
        Item mBoundItem;
        public TodoViewHolder(View itemView) {
            super(itemView);
            mCheckBox = (CheckBox) itemView;
            mCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    if (mBoundItem != null && isChecked != mBoundItem.mIsDone) {
                        onDoneChanged(isChecked);
                    }
                }
            });
        }

        public void bindTo(Item item) {
            mBoundItem = item;
            mCheckBox.setText(item.mText);
            mCheckBox.setChecked(item.mIsDone);
        }

        abstract void onDoneChanged(boolean isChecked);
    }

    private static class Item {
        String mText;
        boolean mIsDone = false;
        final public int id;
        private static int idCounter = 0;

        public Item(String text) {
            id = idCounter ++;
            this.mText = text;
        }
    }
}

答案 2 :(得分:5)

支持库源代码库中有一个示例SortedListActivity,它演示了如何在RecyclerView.Adapter中使用SortedList和SortedListAdapterCallback。从SDK的根目录开始,安装了支持库,它应位于extras/android/support/samples/Support7Demos/src/com/example/android/supportv7/util/SortedListActivity.java(也在github上)。

这些特定样本的存在在Google的文档中提到exactly once,在页面底部处理不同的主题,因此我不会责怪你没有找到它。