什么是 SortedList < T > 用于回收视图。适配器?

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

据说,SortedList是一种新的数据结构,与 RecyclerView.Adapter协同工作,维护 RecyclerView提供的添加/删除/移动/更改的动画。它听起来像 ListView中的 List<T>,但似乎更先进和强大。

那么,SortedList<T>List<T>有什么区别呢?我怎样才能有效地使用它?如果是这样,那么 SortedList<T>List<T>的强制执行是什么?有人能寄点样品过来吗?

如有任何提示或代码,我们将不胜感激。预先感谢。

23908 次浏览

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

源代码可用 给你

来自 文件

一个排序列表实现,可以保持项目的顺序 通知列表中的更改,以便可以将其绑定到 回收视图。适配器。

它使用比较(对象,对象)方法和 使用二进制搜索来检索项 项可能更改,请确保在编辑时调用适当的方法 以避免数据不一致。

控件控制项的顺序并更改通知 SortedList. Callback 参数。

在性能方面,他们还增加了 分类列表,批量回调,以便一次执行多个操作,而不是一次执行一个操作

发送的通知事件进行批处理的回调实现 分类列表。

对象执行多个操作时,此类可能非常有用 但不希望逐个分派每个事件,这可能会导致 导致性能问题。

例如,如果要向 SortedList 添加多个项, 批量回调调用转换单个 onInserted (index,1)调用 如果将项目添加到连续项目中,则添加到一个 onInserted (index,N) 这个更改可以帮助珊瑚视图解决更多的更改 很容易。

如果 SortedList 中的连续更改不适合 批处理时,批处理回调会在出现这种情况时立即调度它们 在对 SortedList 的编辑完成后,必须 始终调用 detchLastEvent ()将所有更改刷新到 Callback。

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

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

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

假设我有10个缓存的项目,当我的回收者列表填充时立即加载。与此同时,我在网络中查询相同的10个条目,因为它们可能在我缓存之后发生了更改。我可以调用相同的 addAll方法,并且 SortedList将在引擎盖下用 fetpedItems 替换 cachedItems (始终保留最后添加的项)。

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

在一个常规的 List中,我会有我所有项目的副本(列表大小为20)。对于 SortedList,它使用 Callback 的 areItemsTheSame替换相同的项。

  1. 何时更新视图是很明智的

在添加 fetpedItems 时,只有当一个或多个 Page的标题发生更改时,才会调用 onChange。您可以自定义 SortedList在回调的 areContentsTheSame中寻找什么。

  1. 它的表演

如果要向 SortedList 中添加多个项,那么如果将项添加到连续的索引中,那么将单个 onInserted (index,1)调用转换为一个 onInserted (index,N)调用。这个更改可以帮助回收视图更容易地解决更改。

样本

您可以在适配器上为 SortedList设置一个 getter,但是我刚刚决定将 helper 方法添加到适配器中。

适配器类别:

  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;
}
}

查看器 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);
}
}

在支持库源代码库中有一个示例 SortedListActivity,它演示了如何在回收视图中使用 SortedList 和 SortedListAdapterCallback。适配器。从 SDK 的根开始,在安装了支持库之后,它应该位于 extras/android/support/samples/Support7Demos/src/com/example/android/supportv7/util/SortedListActivity.java(也在 Github上)。

这些特殊样本的存在是在谷歌的文档中提到的 就一次,在页面的底部处理一个不同的主题,所以我不怪你没有找到它。

SortedListv7 support library

一个 SortedList实现,可以保持项目的顺序 通知列表中的更改,以便可以将其绑定到 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;
}
}
}