RecyclerView Tips(2) SortedListAdapter

来源:互联网 时间:1970-01-01

上一篇说到 Tabs+ViewPager+ListView是最常见的组合,这篇就议一议如何用 RecyclerView快速实现列表页面。

如一个简单的列表场景:TodoList。

分页加载现有Todo现有数据基础上增、删、改

RecyclerView的使用在此就不赘述了,本文主要讨论 RecyclerView.Adapter 的实现

使用最简单的 ArrayList实现,如下:

class ListAdapter extends RecyclerView.Adapter<TodoViewHolder> { final ArrayList<Item> mData; final LayoutInflater mLayoutInflater; public SortedListAdapter(Context context) { mLayoutInflater = LayoutInflater.from(context); mData = new ArrayList<>(); } public void addItem(Item item) { mData.add(item); // 需要自己通知更新 } @Override public TodoViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) { return new TodoViewHolder ( mLayoutInflater.inflate(R.layout.list_todo_item, parent, false)); } @Override public void onBindViewHolder(TodoViewHolder holder, int position) { holder.bindTo(mData.get(position)); } @Override public int getItemCount() { return mData.size(); }}

这样的 Adapter一个显而易见的问题就是,如何 做数据的去重。

添加一项数据:最简单的是在 addItem()之前,遍历一次 mData,定位后再决定是插入还是更新现有数据,并调用 notifyItemInserted(pos)。 添加多个数据:多次重复上面的方法…

对于少量数据来说这样做并不见得有什么问题,而且写得多了,都有自己封装好的诸如 ArrayObjectAdapter之类方便使用。

这样就够了吗?

答案肯定是不。 Android Support Library悄悄给我们提供了一个叫 SortedList 的工具类,它默默的藏在support库的角落中,鲜为人知。

SortedList?

文档对它的定义:

是一个有序列表 数据变动会触发回调 SortedList.Callback 的方法,如 onChanged()

构造一个 SortedList需要实现它的回调 SortedList.Callback,并由其来定义数据的排序和数据的唯一性。

它有一个实现类 SortedListAdapterCallback 就是 RecyclerView.Adapter与 SortedList交互的秘密武器。

示例

改造后的 ListAdapter:

class SortedListAdapter extends RecyclerView.Adapter<TodoViewHolder> { final SortedList<Item> mData; final LayoutInflater mLayoutInflater; public SortedListAdapter(Context context) { mLayoutInflater = LayoutInflater.from(context); mData = new SortedList<Item>(Item.class, new SortedListAdapterCallback<Item>(this){ @Override public int compare(Item t0, Item t1) { // 实现这个方法来定义Item的显示顺序 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) { // 比较两个Item的内容是否一致,如不一致则会调用adapter的notifyItemChanged() return oldItem.mText.equals(newItem.mText); } @Override public boolean areItemsTheSame(Item item1, Item item2) { // 两个Item是不是同一个东西, // 它们的内容或许不一样,但id相同代表就是同一个 return item1.id == item2.id; } }); } public void addItem(Item item) { mData.add(item); // 会通过SortedListAdapterCallback自动通知更新 } ... @Override public int getItemCount() { return mData.size(); }}

虽然相对 ListAdapter代码量变多了,但是调用者却再也不用关心数据的去重与通知更新的问题。这一切都有 SortedListAdapterCallback帮你自动处理好了。

单单只这一个好处其实并不值得劳师动众去改掉现有Adapter使用 SortedList,但它另外还有一个令人称赞并喜爱的功能: 批量更新(Batched Updates)。

就如实现添加多个数据:

void addItems(List<Item> items){ mData.beginBatchedUpdates(); // 开始批量更新 mData.addAll(items); // 更新一批数据 mData.endBatchedUpdates(); // 结束更新}

批量删除:

void deleteItems(List<Item> items){ mData.beginBatchedUpdates(); // 开始批量更新 for(Item item : items){ // 删除一批数据 mData.remove(item); } mData.endBatchedUpdates(); // 结束更新}

等等。

如例子所示,调用 beginBatchedUpdates()之后,所有的对 SortedList操作都会等到 endBatchedUpdates()之后一起生效。

完整的示例见:官方Support库Samples ($ANDROID_SDK/extras/android/support/samples/Support7Demos)

More Tips 列表无序的情况,可以用其id或原始数据List的index来比较排序,只要确保能正确实现 compare即可 如无需批量更新,或无频繁的增删改,其实用前面的 ListAdapter比较好。

总之:如果你的列表需要批量更新或者频繁删改,且刚好有明确的先后顺序,快使用 SortedList。

相关阅读:
Top