tl;dr
AndroidでAPTでガシガシコードを生成してもキャッシュがあればそこまで問題ないはず.
APT
最近のAndroidのライブラリの隆盛を見ていると、Dagger2やAutoValue等アノテーションプロセシングを利用してコンパイル時にソースコードを生成する手法が多いように見受けられます.
パフォーマンス観点やコンパイル時にバグを発見できる利点を考えれば至極当然とも言えますが、コンパイル時に延々とソースコードを生成する事で開発生産性を落とすリスクはないのか、小さなアプリを作成して検証してみました.
リポジトリ
今回、アプリ起動→データを非同期でDBに投入→そのDBからデータを取得→ListViewに表示という至極簡単なアプリを作成しました.
apt moduleではDIにDagger2, シンタックスヘルパーにretrolamda, ORMにDBFlowを利用し、runtime moduleではORMのみActiveAndroidを利用しています.非同期処理には両者ともRxAndroidを利用しています.RxAndroidはAPTとは一切関係ありませんね.
※特に意味はないですがORMのTransactionは不使用です.
検証環境
- MacBook Air (13-inch, Early 2014)
- Processor: 1.4 GHz Intel Core i5
- Memory: 4 GB 1600 MHz DDR3
検証結果
キャッシュ有りとキャッシュ無しの2パターンを各モジュールに対して検証します.
カジュアルに5回ずつ計測しました.
apt/キャッシュなし
一番遅い結果に.
./gradlew clean apt:installDebug --profile
- 1回目: Total time: 50.222 secs
- 2回目: Total time: 1 mins 2.961 secs
- 3回目: Total time: 56.094 secs
- 4回目: Total time: 51.708 secs
- 5回目: Total time: 58.114 secs
apt/キャッシュあり
cleanしない版.初回のみ遅かったですが2回目以降はキャッシュが効いています.
./gradlew apt:installDebug --profile
- 1回目: Total time: 40.626 secs
- 2回目: Total time: 15.505 secs
- 3回目: Total time: 14.077 secs
- 4回目: Total time: 13.445 secs
- 5回目: Total time: 14.545 secs
runtime/キャッシュなし
キャッシュが無い状況下では当然ですがruntime moduleの方が速かったです.
./gradlew clean runtime:installDebug --profile
- 1回目: Total time: 39.917 secs
- 2回目: Total time: 46.036 secs
- 3回目: Total time: 38.881 secs
- 4回目: Total time: 38.833 secs
- 5回目: Total time: 37.06 secs
runtime/キャッシュあり
aptモジュールより僅かに速いですが無視できる範囲です.
./gradlew runtime:installDebug --profile
- 1回目: time: 14.02 secs
- 2回目: Total time: 14.019 secs
- 3回目: Total time: 14.687 secs
- 4回目: Total time: 13.702 secs
- 5回目: Total time: 13.63 secs
まとめ
今回の実験では、キャッシュが効いている状況下であればaptでも通常のコンパイルと遜色ない結果となりました.
但し、今回作成したアプリは超小規模&DBやレトロラムダも僅かな箇所しか使っていないので、プロダクトレベルまでコードベースが膨れてくるともしかしたら体感できる差が現れるかもしれません.
Android Studioでポチポチして開発してしまうと余計なコマンドが発行されて遅くなると思うのでコマンドで開発した方が良いと思います.