19
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

qnoteAdvent Calendar 2017

Day 16

MergeRecyclerAdapter使って、複雑なデータ構造のRecyclerViewを簡単に実装しよう

Posted at

さて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の記事を書きたいなと思っています。

19
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?