Studyplus Engineering Blog

スタディプラスの開発者が発信するブログ

AAC Pagingライブラリ導入の話

お久しぶりです。Androidエンジニアの若宮(id:D_R_1009)です。 今日はAndroid Architecture Components Pagingライブラリ(AAC Paging)の導入例を紹介したいと思います。

アプリを利用してくださっている方はお気づきになられていると思いますが、11月19日よりアプリのデザインを一新しました。 デザインの変更に伴い、アプリ起動時の通信処理や各Fragmentの生成処理の見直しを行いました。安定性が増すことを目標に、見直しに取り組みました。

デザインのアップデートとほぼ同時ではあるのですが、タイムラインのパフォーマンス改善にも取り組みました。 今回は、パフォーマンス改善でAAC Pagingライブラリを導入した際のアレコレを書きたいと思います。

AAC Pagingライブラリとは

https://developer.android.com/topic/libraries/architecture/paging/

AACライブラリの一つとして2018年6月に正式リリースされた、ローカルDBやリモートサーバーから逐次データを読み込む処理をサポートしてくれるライブラリです。 データ読み込みの処理と表示するデータの保持を分けることで、RecyclerViewのスクロール処理がデータの読み込み処理によって遅くならない等の効果が期待できます。

個人的には recyclerview.extensions.ListAdapter がsupportライブラリに入った頃から気になっている存在です。 そのため「ようやく正式版になってくれたか」という気分ですね。

導入に当たって検討した事柄

旧タイムライン処理にはいくつかの課題がありました。一部を抜粋すると下記の通りです。

  • 追加読み込み処理が「最後から5番目」を表示したタイミングになるため、読み込み処理がUI処理に強く依存している
  • リストのデータがRecyclerView.Adapterで保持されているため、Fragmentの破棄時にキャッシュが削除されてしまう
  • ObservableListを利用しているため、通信取得処理のスレッドとUI更新時のスレッドをFragment内で明示的に切り替える必要がある

Pagingライブラリの導入によって次のように解決すると考えました。

  • 追加読み込みのタイミングがPagingライブラリ側でハンドリングされるため、読み込みの通信処理に専念できる
  • リストのデータをメモリやディスク上で保持できるため、Fragmentの破棄時に(不要な)キャッシュ削除が発生しない
  • LiveDataでリストの取得ができるため、UIスレッドとそのほかのスレッドをほぼ意識しないで済む(ViewModel + LiveDataの処理にまとめられる)

導入方法

前述の通り、Pagingライブラリを導入していた時期はアプリのデザインリニューアルの時期とかぶっています。 また導入事例や導入LTなどをあまり見つけることもできなかったため、いくつか安全策をとることとしました

旧タイムライン処理との平行運用

通信時のパースクラスから表示用のFragmentまで、旧タイムラインの処理と切り離して全て新規作成することとしました。 他の新規開発機能とのバッティングを抑え、ライブラリの導入に失敗した場合や想定以上の工数を使ってしまった場合に備えるためです。 結果としてタイムラインを置き換えることはできましたが、タイムラインの一部のみ置き換えることを想定しました。

良かった点

  • 旧タイムラインを置き換え可能な箇所から書き換えることができたため、レビューのコストが想定より低くなった
  • 一部のみの置き換えを念頭に置いて設計した結果、依存度の低いコード記述となった
  • 旧タイムラインは主にJavaで記述されていたが、新タイムラインはKotlinで記述することができ、data classを活用できた

悪かった点

  • JSONのパースクラスから作り直したところ、RecyclerViewのItemレイアウトが使い回せなくなってしまった
  • 旧タイムラインに追加された修正を新タイムラインに反映させていたが、反映漏れが発生した

その他に新しくなった箇所

旧タイムラインのItemをconstraint layoutに置き換えたところ、View間の関係性が漏れていた箇所が多数ありました。 Viewの縦横のサイズ計算に関わる問題となるため、ネストが浅くなるようリファクタリングを行なっています。

また、タイムラインのFragment間でRecyclerViewのViewPoolを共有し、Inflate回数を減らす対応を行いました。 こちらは2018年のDroidKaigiより広く使われている手法なので、弊社アプリもようやく追いついた感覚があります。

感想

導入のためサンプルコードをPCに落としてから、機能としてリリースするまで3週間ほどかかりました。 ほとんどPagingライブラリの導入にかかりきりだったので、長い時間をかけたような気がしています。

導入時に想定していたほど、Pagingライブラリの導入にはコストがかかりませんでした。 これは公式で非常にわかりやすいサンプルプロジェクトが用意されていたことが大きいです。まず公式サンプルに従ってAPIとDBの接続をするのが良さそうです。

逆に想定しきれていなかったのが、レイアウト周りの修正の多さです。 もともとButterKnifeをDataBindingに置き換えている途中だったこともあり、Kotlinとxmlの両方で書き換え処理が多くなりました。 変更に強いデータ構造を作らなければならない、という強い反省になったと感じています。

ひとこと

バリバリAACを使っていきたい! という気持ち溢れるエンジニアがいましたらこちらよりご連絡ください。