Jetpack Compose は、UI 開発を加速させ、Android エンジニアの生産性を高めます。しかし、新しいツールをプロジェクトに追加する際は、APK、ビルド、実行時のパフォーマンスに影響する可能性があるため、注意が必要です。
APK サイズとビルド時間
このセクションでは、Jetpack Compose の追加または Jetpack Compose への移行を行うと、2 つの異なるアプリがどのような影響を受けるかを比較します。
- Tivi は Compose に完全に移行し、AppCompat ライブラリとマテリアル デザイン コンポーネント ライブラリは削除されました。
- Sunflower(
compose_recyclerview
ブランチ)では、RecyclerView
のアイテムに対して使用する場合にのみ Compose が追加されます。他のすべての依存関係は以前と同じです。
APK サイズ
プロジェクトにライブラリを追加すると、APK サイズに影響します。Compose が上記のプロジェクトのサイズにどのように影響するかを見てみましょう。以下に示す結果は、リソースとコードの圧縮が有効になっていて、R8 フルモードを使用している場合に、APK Analyzer で測定された各プロジェクトの圧縮リリース APK の結果です。
Tivi では APK サイズが 46% 削減され、4.49 MB から 2.39 MB になりました。また、Compose に完全に移行した後、メソッド数が 17% 削減されました。XML コードの行数は 76% 削減されました。
Compose をプロジェクトに追加すると、Sunflower の APK サイズは 575 KB 増加し、2,407 KB から 2,982 KB になりました。その Sunflower ブランチで Compose が使用されることはほとんどないので、プロジェクトには、Compose のみの APK サイズのメリット(プロジェクトから AppCompat への依存関係が削除されるなど)はありません。
ビルド時間
同じプロジェクトを使用して、Compose がビルドのパフォーマンスに及ぼす影響を測定してみましょう。
このテストでは、デバッグビルド時間(開発中に考慮すべき時間)を考慮します。
Compose に移行する前の Tivi の平均ビルド時間は 108.71 秒でした。Compose に完全に移行した後、平均ビルド時間は 76.96 秒に短縮されました。ビルド時間は 29% 短縮されました。これだけ時間が短縮された主な原因は、kapt アノテーション プロセッサを使用するプロジェクトからデータ バインディングと Epoxy を削除できたことと、AGP 7.0 で Hilt が高速化されたことです。
一方、Sunflower ではビルド時間の中央値は 7.6% 増加し、11.57 秒から 12.45 秒になりました。
まとめ
アプリへの Compose の導入を開始すると、APK サイズとビルド時間が増加することがあります。しかし、プロジェクトを Compose に完全に移行すると、それらは減少して指標は移行前より向上します。
実行時のパフォーマンス
このセクションでは、Jetpack Compose の実行時のパフォーマンスに関するトピックを取り上げ、Jetpack Compose とビューシステムのパフォーマンスの比較および測定方法について説明します。
スマート再コンポジション
UI の一部が無効な場合、Compose は更新が必要な部分のみを再コンポーズするために最善を尽くします。このトピックについて詳しくは、コンポーザブルのライフサイクル ガイドをご覧ください。
ビューシステムとの比較
ビューシステムから学んだ設計と教訓により、Jetpack Compose はビューシステムより優れたパフォーマンスを発揮します。
すべてがビューの拡張
あらゆるユースケースをサポートするには、画面に描画されるすべての View
(TextView
、Button
、ImageView
など)で、メモリ割り当て、明示的な状態トラッキング、さまざまなコールバックが必要になります。さらに、カスタム View
オーナーは、明示的なロジックを実装して、データの反復処理などにおける不要な再描画を回避する必要があります。
Jetpack Compose は、いくつかの方法でこの問題に対処します。Compose には、ビューを描画するための明示的な更新可能オブジェクトはありません。UI 要素はシンプルなコンポーズ可能な関数であり、その情報は再現可能な方法で Composition に書き込まれます。これにより、上記の機能を必要とするコンポーザブルのみで明示的な状態トラッキング、メモリ割り当て、コールバックが削減され、特定の View
タイプのすべての拡張でそれらが要求されることはありません。
さらに Compose は、すぐに使用できるスマート再コンポジション機能を備えており、変更が不要な場合は以前の描画結果が再現されます。
複数のレイアウトパス
従来の ViewGroup では、測定とレイアウト用の API の表現力が豊富なので、複数のレイアウトパスが簡単に生成されます。こうした複数のレイアウトパスは、ビュー階層内の特定のネストポイントで実行されると、指数関数的な処理を発生させる可能性があります。
Jetpack Compose は、API コントラクトを介してすべてのレイアウト コンポーザブルに単一のレイアウトパスを強制適用します。これにより、Compose は深い UI ツリーを効率的に処理できます。複数回の測定が必要な場合、Compose では固有の測定値という特別なシステムを利用できます。
起動時のパフォーマンスを確認する
ビューシステムでは、特定のレイアウトを初めて表示する際に、XML レイアウトをインフレートする必要があります。Jetpack Compose では、レイアウトが Kotlin で記述されており、アプリの他の部分と同様にコンパイルされるため、コストが削減されます。
Compose のベンチマーク
Jetpack Compose 1.0 では、debug
モードと release
モードでアプリのパフォーマンスに顕著な違いがあります。アプリをプロファイリングする際は、代表的な時間指標については debug
ビルドではなく必ず release
ビルドを使用してください。
Jetpack Compose コードのパフォーマンスを確認するには、Jetpack Macrobenchmark ライブラリを使用できます。Jetpack Compose との併用方法については、MacrobenchmarkSample プロジェクトをご覧ください。Jetpack Compose チームも、このライブラリを使用して、発生する可能性がある回帰を検出しています。たとえば、こちらの遅延列のベンチマークと、回帰をトラッキングしているダッシュボードをご覧ください。
Compose プロファイルのインストール
Jetpack Compose はバンドルされていないライブラリであるため、ビューシステムの UI ツールキットのクラスおよびドローアブルをプリロードする Zygote のメリットは得られません。Jetpack Compose 1.0 は、リリースビルドでプロファイル インストールを利用します。プロファイル インストーラを使用すると、インストール時に事前コンパイルする重要なコードを指定できます。Compose には、Compose アプリの起動時間を短縮してジャンクを減らすためのプロファイル インストール ルールが付属しています。