さてMergeRecyclerAdapterを知っていますか?
これはRecyclerViewで使うRecyclerView.Adapterを拡張したものです。
https://github.com/cattaka/AdapterToolbox/blob/master/adapter-toolbox/src/main/java/net/cattaka/android/adaptertoolbox/thirdparty/MergeRecyclerAdapter.java
確か1年位前に見つけ、今でもバリバリ使っています。
実際にどのように使うのかお伝えしたいと思います。
#導入
MergeRecyclerAdapterはGitHabで公開されております。
ライセンスもapache2.0なので問題いなく使えますね。
僕の場合は直接ファイルを直接取り込んで使っています。
RecyclerView recyclerView = ((RecyclerView) findViewById(R.id.list));
recyclerView.setLayoutManager(new LinearLayoutManager(this));
MergeRecyclerAdapter<BaseAdapter> mergeRecyclerAdapter = new MergeRecyclerAdapter<>(this);
mergeRecyclerAdapter.addAdapter(new HeaderAdapter("aHeader"));
AAdapter aAdapter = new AAdapter(aList, "aTag");
mergeRecyclerAdapter.addAdapter(aAdapter);
mergeRecyclerAdapter.addAdapter(new FooterAdapter("aFooter"));
mergeRecyclerAdapter.addAdapter(new HeaderAdapter("bHeader"));
BAdapter bAdapter = new BAdapter(bList, "bTag");
mergeRecyclerAdapter.addAdapter(bAdapter);
mergeRecyclerAdapter.addAdapter(new FooterAdapter("bFooter"));
mergeRecyclerAdapter.addAdapter(new HeaderAdapter("cHeader"));
AAdapter cAdapter = new AAdapter(cList, "cTag");
mergeRecyclerAdapter.addAdapter(cAdapter);
mergeRecyclerAdapter.addAdapter(new FooterAdapter("cFooter"));
recyclerView.setAdapter(mergeRecyclerAdapter);
簡単に書くとこのような感じです。
A要素B要素C要素があり、それぞれの塊ごとにheader,footerを持つリストを作っています。
A要素とC要素は同じデータ構造をしています。
HeaderAdapter、FooterAdapter、A要素を表示するAAdapter、B要素を表示するBAdapterを作成しておきます。
C要素に関してはA要素と同じデータ構造なのでAAdapterを使いまわします。
これらのadapterはBaseAdapterというTagを保持できるRecyclerView.Adapterを継承しています。
まず各adapterを生成してMergeRecyclerAdapterに追加していきます。
そしてMergeRecyclerAdapterをrecyclerViewにセットしてあげます。
これで表示までは完了です。
とても簡単ですね。
リストにクリックに関してはDataBinding+ViewModelを用いて行のレイアウトに直接onClickListenerを設定し、EventBusにてActivityやFragmentに通知を行いハンドリングを行っています。
#メリット
使った上で気がついたメリットを何点かあげます。
Adapterが大きくならない
1つのadapter内で別のデータを扱わないので、データの型の確認をしてlayoutやviewModel指定しなくてよい
汎用性が増す
データの型ごとにadapterを作るので、1画面1adapterにならず、adapterの使い回しが容易
複数の配列を組み合わせる時のpositionを考慮しなくて良い
adapterごとにpositionが0から取れるのでIndexOutOfBoundsExceptionが起きにくい
全件分のデータ取得を待つ必要がない
adapterごとにデータがあればいいので、複数APIでデータを取得するとしても取得したところから表示ができる
その場合は先にadapterを生成してMergeRecyclerAdapterに渡し、データ取得後にnotifyDataSetChanged()などで変更を通知すれば良い
#デメリット
クラスの数がとても増える
これがデメリットになるかは毎度問題になりますが、しいて挙げるならこれくらいになるでしょうか。
#まとめ
サンプルでは各adapterがtagを持っていますが実際には使う機会は少ないです。
例えばpagingをする必要があり、なおかつpagingしたブロックごとに何かをしないといけない場合とか。
adapterの持つデータに関して何か行う場合に、同じ型のadapterが複数ある可能性があるのでその時の対応策です。
これを使って思ったのがiOSのtableViewのセクションと同じような動作をさせられること
分割してデータを入れられたり簡単にheder,footerが入れられたり、メリットが沢山あるものです。
ご覧の通りAdvent Calendar 2017の記事になるのですが、本当はGoogle Homeのことを書きたかったのですが、思ったとおりに動かすことができず、断念。
急遽この内容に変更しました。
近いうちにつまずいたところも含めGoogle Homeの記事を書きたいなと思っています。