読者です 読者をやめる 読者になる 読者になる

Septeni Engineer's Blog

セプテーニエンジニアが綴る技術ブログ

RecyclerViewのデータ管理をSortedListに丸投げする

こんにちは、ゆのうえです。
Android Support Library 22.1.0からv7 recyclerview libraryにSortedListというクラスが追加されています。
特に必要とされていないのか、同様のふるまいを自力で実装している人が多いのかあまり話題には上りませんが、RecyclerViewのお伴としてなかなか便利なクラスでしたのでご紹介したいと思います。


役割

名前の通り、RecyclerView上のリストのソートを自動で行うほか、データの重複や更新チェックなどしてくれます。ページングでリストに次々とデータを追加するような場面で活躍しそうです。
詳細は、簡単な実装方法とともに紹介したいと思います。

実装

SortedListはリストに追加するデータクラスと、リストに変更があった際のふるまいを決めるコールバックとともに宣言されます。

SortedList sortedList = new SortedList(MyData.class, new MyCallback());

具体的な機能は、このコールバックの実装メソッドを見ると分かりやすいです。
 

  • compare(T2 o1, T2 o2)
    データの順番を決定します。
    リスト内の順番は、追加順に関わらずこの実装によって決定されます。
    Comparator.compare()と仕様は同じです。
    o1がo2より前ならば負の値、後ならば正の値、同じならば0を返します。
     

  • areContentsTheSame(T2 oldItem, T2 newItem)
    リスト内のデータが変更された際、更新通知を行うかどうかを決定します。
    ここでtrueを返すとonChanged()(※後述)が呼ばれません。
     

  • areItemsTheSame(T2 item1, T2 item2)
    リストにデータが追加された際、既に存在するデータとの比較を行います。
    既存データとみなされたデータは、リストに追加されません。
    ユニークIDの比較などをここでしておくと重複表示が防げます。
     

  • onChanged(int position, int count)
    リスト内のデータに変更があった場合に呼ばれます。
     

  • onInserted(int position, int count)
    リストに新しいデータが追加された場合に呼ばれます。
     

  • onMoved(int fromPosition, int toPosition)
    データの順番に変更があった場合に呼ばれます。
     

  • onRemoved(int position, int count)
    データがリストから削除された場合に呼ばれます。
     

あとは普段のListクラスのようにAdapterに組み込んで、RecyclerViewに設定してあげましょう。
それぞれのon〜でAdapterに更新通知をするとよいと思います。

SortedListが面白いのは、更新のバッチ処理が作成できる所です。
beginBatchedUpdates()endBatchedUpdates()で囲んだ処理をまとめることができます。
例えば、

sortedList.beginBatchedUpdates();
sortedList.add(data1);
sortedList.add(data2);
sortedList.add(data3);
sortedList.endBatchedUpdates();

と書くと、onInserted()が1度だけ呼ばれます。
無駄な更新通知が行われないほか、RecyclerViewのアニメーションとも相性がいい機能です。
ちなみに、SortedListはListと名前がついているくせにCollectionを実装しておらず、addAll()が存在しません。
22.1.0時点ではclear()もなかったと記憶しているのですが、いつの間にか追加されていました。

サンプルコード

お約束のサンプルコードを用意しました。
簡単な要素の追加と削除の挙動が確認できます。
本当はソートの定義を差し替えて並び替えができるように…と思っていたのですが手付かず。。。

まとまった追加・削除、重複チェックなどが簡単に実装できるので、知っておくと役に立ちそうなクラスです。
 

Qiitaにも同じ内容で投稿しています。