什么是SortedList <T>与RecyclerView.Adapter一起工作?

Android支持库22.1昨天发布。 v4支持库和v7中增加了许多新function,其中android.support.v7.util.SortedList<T>引起了我的注意。

据说SortedList是一个新的数据结构,与RecyclerView.Adapter ,维护RecyclerView.Adapter的项目添加/删除/移动/更改的animation。 这听起来像ListViewList<T> ,但似乎更先进和强大。

那么, SortedList<T>List<T>什么区别呢? 我怎么能有效地使用它? 如果是这样,那么SortedList<T>List<T>上的执行是什么? 有人可以张贴一些样本吗?

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

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

SortedListList之间的一个区别在下面的示例中的addAll帮助程序方法中。

 public void addAll(List<Page> items) { mPages.beginBatchedUpdates(); for (Page item : items) { mPages.add(item); } mPages.endBatchedUpdates(); } 
  1. 保持最后添加的项目

假设我有10个caching项目,当我的回收站列表填充时立即加载。 与此同时,我查询了我的networking的相同的10个项目,因为他们可能已经改变,因为我caching他们。 我可以调用相同的addAll方法,并且SortedList将用引擎盖下的fetchedItemsreplacecachedItems(始终保留最后一个添加的项目)。

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

在一个普通的List ,我会重复所有的项目(列表大小为20)。 使用SortedListreplace使用Callback的areItemsTheSame相同的areItemsTheSame

  1. 它聪明的时候更新视图

当fetchedItems被添加时, onChange将只被调用,如果一个或多个Page的标题改变。 您可以自定义SortedList在callback的areContentsTheSame查找的areContentsTheSame

  1. 它的性能

如果要将多个项目添加到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(); } } 

页面类:

 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> 

Viewholder类:

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

SortedListv7 support library

一个SortedList实现,可以保持项目的顺序,并通知列表中的变化,以便它可以绑定到一个RecyclerView.Adapter

它使用compare(Object, Object)方法保存项目compare(Object, Object)并使用二进制search来检索项目。 如果您的项目的sorting标准可能会更改,请确保在编辑时调用适当的方法以避免数据不一致。

您可以通过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; } } } 

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

这些特定样本的存在在Google的文档中只提到过一次 ,在处理不同主题的页面底部,所以我不会责怪你没有find它。

关于SortedList实现,它由<T>数组支持,默认最小容量为10个项目。 一旦数组已满,数组的大小调整为size() + 10

源代码在这里可用

从文档

一个Sorted列表实现,可以保持项目的顺序,并通知列表中的更改,使其可以绑定到RecyclerView.Adapter。

它使用compare(Object,Object)方法保存项目,并使用二进制search来检索项目。 如果您的项目的sorting标准可能会更改,请确保在编辑时调用适当的方法以避免数据不一致。

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

关于性能,他们还添加了SortedList.BatchedCallback来一次执行多个操作,而不是一个

一个callback实现,可以批量通知由SortedList调度的事件。

如果您想要对SortedList执行多个操作,但不想逐个分派每个事件,则可能会出现此类,这可能会导致性能问题。

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

如果SortedList中的连续更改不适合批处理,则一旦检测到这种情况,BatchingCallback就会调度它们。 SortedList编辑完成后,您必须始终调用dispatchLastEvent()刷新对callback的所有更改。