作成指標とビュー指標を比較する

Jetpack Compose は、UI 開発を加速し、Android 開発を改善します。ただし、既存のアプリに Compose を追加すると、アプリの APK サイズ、ビルド、実行時のパフォーマンスなどの指標に影響する可能性があることを考慮してください。

APK サイズとビルド時間

このセクションでは、ビューベースのアプリを Compose に移行する際のおすすめの方法を示すアプリである Sunflower サンプルアプリを例に、APK サイズとビルド時間への影響について説明します。

APK サイズ

ライブラリをプロジェクトに追加すると、APK のサイズが増加します。次の結果は、リソースとコードの圧縮を有効にし、R8 フルモードを使用して、APK Analyzer で測定した、各プロジェクトの縮小されたリリース APK のものです。

視聴回数のみ ビューと Compose の混在 Compose-only
ダウンロード サイズ 2,252 KB 3,034 KB 2,966 KB

Sunflower に Compose を初めて追加したとき、APK のサイズは 2,252 KB から 3,034 KB に増加しました。つまり、782 KB 増加しました。生成された APK は、ビューと Compose を組み合わせて作成された UI で構成されていました。Sunflower に依存関係が追加されたため、この増加は想定内です。

一方、Sunflower を Compose 専用アプリに移行したところ、APK サイズは 3,034 KB から 2,966 KB に減少し、68 KB 減少しました。この減少は、AppCompat や ConstraintLayout などの未使用の View 依存関係を削除したことによるものです。

ビルド時間

Compose を追加すると、Compose コンパイラがアプリ内のコンポーザブルを処理するため、アプリのビルド時間が長くなります。次の結果は、スタンドアロンの gradle-profiler ツールを使用して取得したものです。このツールは、ビルドを複数回実行して、Sunflower のデバッグ ビルド時間の平均ビルド時間を取得します。

gradle-profiler --benchmark --project-dir . :app:assembleDebug
視聴回数のみ ビューと Compose の混在 Compose-only
平均ビルド時間 299.47 ミリ秒 399.09 ミリ秒 342.16 ミリ秒

Sunflower に Compose を初めて追加したとき、平均ビルド時間は 299 ミリ秒から 399 ミリ秒に増加しました。つまり、100 ミリ秒増加しました。この時間は、プロジェクトで定義された Compose コードを変換するために Compose コンパイラが追加のタスクを実行しているためです。

逆に、Sunflower の Compose への移行が完了すると、平均ビルド時間は 342 ミリ秒に減少し、57 ミリ秒の短縮となりました。この短縮は、データ バインディングの削除、kapt を使用する依存関係の KSP への移行、複数の依存関係の最新バージョンへの更新など、ビルド時間を短縮する複数の要因によるものです。

概要

Compose を採用すると、アプリの APK サイズが効果的に増加し、Compose コードのコンパイル プロセスによりアプリのビルド時間パフォーマンスも向上します。ただし、これらのトレードオフは、Compose のメリット、特に Compose を採用した際の開発者の生産性の向上と照らし合わせて検討する必要があります。たとえば、Google Play ストア チームは、UI の作成に必要なコードが大幅に減り、場合によっては 50%削減されることを発見しました。これにより、生産性とコードの保守性が向上します。

その他の事例紹介については、チームでの Compose の採用をご覧ください。

実行時のパフォーマンス

このセクションでは、Jetpack Compose のランタイム パフォーマンスに関連するトピックについて説明します。Jetpack Compose のパフォーマンスと View システムのパフォーマンスを比較する方法や、パフォーマンスを測定する方法について理解を深めることができます。

スマート再コンポジション

UI の一部が無効な場合、Compose は更新が必要な部分のみを再コンポーズしようとします。詳しくは、コンポーザブルのライフサイクルと Jetpack Compose のフェーズのドキュメントをご覧ください。

ベースライン プロファイル

ベースライン プロファイルは、一般的なユーザー ジャーニーを高速化する優れた方法です。アプリにベースライン プロファイルを含めると、含まれるコードパスに対して解釈とジャストインタイム(JIT)コンパイルの手順を行う必要がなくなるため、初回起動からのコード実行速度が約 30% 向上します。

Jetpack Compose ライブラリには独自のベースライン プロファイルが含まれており、アプリで Compose を使用すると、これらの最適化が自動的に適用されます。ただし、これらの最適化は Compose ライブラリ内のコードパスにのみ影響するため、Compose 以外のコードパスをカバーするために、アプリにベースライン プロファイルを追加することをおすすめします。

ビューシステムとの比較

Jetpack Compose には、View システムに比べて多くの改善点があります。これらの改善点については、以降のセクションで説明します。

すべてがビューの拡張

あらゆるユースケースをサポートするには、画面に描画されるすべての View(TextView、Button、ImageView など)で、メモリ割り当て、明示的な状態トラッキング、さまざまなコールバックが必要になります。さらに、カスタム View オーナーは、不要な再描画(たとえば、繰り返しデータ処理)を防ぐための明示的なロジックを実装する必要があります。

Jetpack Compose は、いくつかの方法でこの問題に対処します。Compose には、ビューの描画用の明示的な更新可能なオブジェクトはありません。UI 要素は、情報が再生可能な方法でコンポーズに書き込まれるシンプルなコンポーズ可能な関数です。これにより、明示的な状態の追跡、メモリ割り当て、コールバックを、特定の View 型のすべての拡張機能で必要とするのではなく、これらの機能を必要とするコンポーザブルのみに限定できます。

さらに、Compose はスマートな再コンポーズを提供します。変更する必要がない場合は、以前に描画された結果を再生します。

複数のレイアウトパス

従来の ViewGroup には、測定とレイアウトの API に多くの表現力があり、複数のレイアウト パスが発生しやすくなっています。こうした複数のレイアウトパスは、ビュー階層内の特定のネストポイントで実行されると、指数関数的な処理を発生させる可能性があります。

Jetpack Compose は、API コントラクトを介して、すべてのレイアウト コンポーザブルに単一のレイアウト パスを適用します。これにより、Compose は深い UI ツリーを効率的に処理できます。複数回の測定が必要な場合、Compose には固有の測定値が用意されています。

起動時のパフォーマンスを確認する

ビューシステムでは、特定のレイアウトを初めて表示する際に、XML レイアウトをインフレートする必要があります。レイアウトは Kotlin で記述され、アプリの他の部分と同様にコンパイルされるため、このコストは Jetpack Compose に保存されます。

Compose のベンチマーク

Jetpack Compose 1.0 では、debug モードと release モードでアプリのパフォーマンスに顕著な違いがあります。アプリをプロファイリングする際は、代表的な時間指標については debug ビルドではなく必ず release ビルドを使用してください。

Jetpack Compose コードのパフォーマンスを確認するには、Jetpack Macrobenchmark ライブラリを使用できます。Jetpack Compose との併用方法については、MacrobenchmarkSample プロジェクトをご覧ください。

Jetpack Compose チームも、Macrobenchmark を使用して、発生する可能性がある回帰を検出しています。たとえば、こちらの遅延列のベンチマークと、回帰をトラッキングしているダッシュボードをご覧ください。

Compose プロファイルのインストール

Jetpack Compose はバンドルされていないライブラリであるため、View システムの UI ツールキット クラスとドローアブルをプリロードする Zygote のメリットはありません。Jetpack Compose 1.0 は、リリースビルドにプロファイル インストールを利用します。プロファイル インストーラを使用すると、アプリはインストール時に事前(AOT)コンパイルされるクリティカル コードを指定できます。Compose には、Compose アプリの起動時間を短縮してジャンクを減らすためのプロファイル インストール ルールが付属しています。