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

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

APK サイズとビルド時間

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

APK サイズ

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

表示専用 ビューと Compose の混在 Compose のみ
ダウンロード サイズ 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 のみ
平均ビルド時間 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(TextView、Button、ImageView など)で、メモリ割り当て、明示的な状態トラッキング、さまざまなコールバックが必要になります。さらに、カスタム View のオーナーは、不要な再描画(反復的なデータ処理など)を防ぐために、明示的なロジックを実装する必要があります。

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

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

複数のレイアウトパス

従来の ViewGroup は、measure API と layout 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 チームも、Macrobenchmark を使用して、発生する可能性がある回帰を検出しています。たとえば、こちらの遅延列のベンチマークと、回帰をトラッキングしているダッシュボードをご覧ください。

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

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