Android
AndroidStudio
android開発
RecyclerView

RecyclerView.Adapterのnotify系メソッド 〜 notifyDataSetChangedで…いいの?


12月1日は「データセンターの日」とのことで……

今日は何の日によると、12月1日は「データセンターの日」という記念日だそうな。Data CenterとDeCemberが雰囲気似ているという理由から、ソフトバンクIDC(現IDCフロンティア)が制定したんだとか。


というわけで、「データ」にまつわるAndroid

CafeSnapというアプリでは、Design Support Libraryを使用して、マテリアルデザインを導入しつつあります。マテリアルデザインの設計思想では、これまでのOSより自由で、魅力的なモーションを用いたUIが、比較的簡単に実装できるようになりました。

今日は、マテリアル化をすすめる中で遭遇した、RecyclerViewに渡すデータの「更新」に関するメソッドを、まとめてみることにします。


そもそもRecyclerViewって…

RecyclerViewは、しばしばGridViewやListViewなどの、データ一覧を表示するViewと比較されますが、RecyclerViewは少し違います。GridViewやListViewが、データを表示することに特化していると思いますが、RecyclerViewはリストのアイテムを操作する方に寄っているように思います。


notifyDataSetChangedばかり使っていないか

とりあえずadapterに渡しているobjectにaddしたりaddAllしたら、とりあえずnotifyDataSetChangedしてませんか。そもそもnotifyDataSetChangedは、リスト全体を更新するためのメソッド。ページングのためのメソッドではない。他に何かあるの。


RecyclerView.Adapterのnotify系メソッド一覧

ListViewやGridViewなどありますが、今回はRecyclerViewのnotify系メソッドをまとめます。

今後のことも考えて、RecyclerViewを使えるようになるのは大事な気がしたので。

RecyclerView.Adapter | Android Developers

こちらをなんとなく翻訳してみます。


notifyDataSetChanged()

final void notifyDataSetChanged()

データセットが変更されたことを、登録されているすべてのobserverに通知する。

RecyclerViewに表示されているItem全体に更新をかけるようです。Item内でアニメーション(例えばフェードインとか)を使用しているViewがあると、すべてのItemのアニメーションが実行されます。


notifyItemChanged(int position)

final void notifyItemChanged(int position)

指定したpositionのitemが変更されたことを、登録されているすべてのobserverに通知する。

adapterにindexOf()とかメソッドを作っておくと、実装しやすくなったりします。


Adapterの実装例

List<MyModel> _objects;

public int indexOf(MyModel object) {
return _objects.indexOf(object);
}



ActivityやFragment側の実装例

// 初期化済みとする

MyRecyclerViewAdapter _adapter;

// 仮に、Itemが変化したことを通知するコールバックがあったとして……
public void onItemChanged(MyModel object) {
int position = _adapter.indexOf(object);
_adapter.notifyItemChanged(position);
}


OnClickとかのリスナは、結局Adapterにつけるしかないのですかね、なんだか変な感じがしますが……。


notifyItemChanged(int position, Object payload)

final void notifyItemChanged(int position, Object payload)

これはまだ使った経験のないメソッドですが、どうやら……

positionのitemをpayloadで渡したオブジェクトで交換してくれる、というものなのだと思います。

普段は、自分でaddAllみたいなメソッドを実装しなくても、Object渡したら交換できちゃうってことなのだと思います。


payloadで渡したUIオブジェクトの部分を更新できると言うもののようです。

詳しい実装方法は、こちらの記事に書いてありました!↓

RecyclerView の notifyItemChanged をもっと便利に使う


notifyItemInserted(int position)

final void notifyItemInserted(int position)

指定したpositionに新しいitemが挿入されたことを、登録されているすべてのobserverに通知する。


notifyItemMoved(int fromPosition, int toPosition)

final void notifyItemMoved(int fromPosition, int toPosition)

fromPositionのitemが、toPositionへ移動したことを、登録されているすべてのobserverに通知する。


notifyItemRangeChanged(int positionStart, int itemCount)

final void notifyItemRangeChanged(int positionStart, int itemCount)

positionStartの位置からitemCountの範囲において、データの変更があったことを登録されているすべてのobserverに通知する。


notifyItemRangeChanged(int positionStart, int itemCount, Object payload)

final void notifyItemRangeChanged(int positionStart, int itemCount, Object payload)

positionStartの位置からitemCountの範囲において、データの変更があったことを登録されているすべてのobserverに通知する。

このメソッドも使ったことないけど、payloadに入れたオブジェクトで更新してもらえるんだと思います。

違うのかな……???


payloadで渡したUIオブジェクトの部分を更新できると言うもののようです。

詳しい実装方法は、こちらの記事に書いてありました!↓

RecyclerView の notifyItemChanged をもっと便利に使う


notifyItemRangeInserted(int positionStart, int itemCount)

final void notifyItemRangeInserted(int positionStart, int itemCount)

positionStartの位置からitemCountの範囲において、データの変更があったことを登録されているすべてのobserverに通知する。


notifyItemRangeRemoved(int positionStart, int itemCount)

final void notifyItemRangeRemoved(int positionStart, int itemCount)

positionStartを先頭にitemCountの範囲のitemがデータセットから削除されたことを、登録されているすべてのobserverに通知する。


notifyItemRemoved(int position)

final void notifyItemRemoved(int position)

指定したpositionに存在したitemがデータセットから削除されたことを、登録されたすべてのobserverに通知する。

このメソッドを呼ぶと、消えた行を埋めるようにアニメーションされてかっこいい!

こんな感じで。

みなさんのRecyclerView、RecyclerView.Adapter実装の参考になればと思います。