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

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

APK サイズとビルド時間

このセクションでは、Sunflower サンプルアプリ(View ベースのアプリを Compose に移行する際のおすすめの方法を示すアプリ)を例に、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 減少しました。この減少は、AppCompatConstraintLayout などの未使用の 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 を採用すると、Compose コードのコンパイル プロセスにより、アプリの APK サイズが効果的に増加し、アプリのビルド時間パフォーマンスも向上します。ただし、これらのトレードオフは、Compose のメリット、特に Compose を採用した際の開発者の生産性の向上と照らし合わせて検討する必要があります。たとえば、Play ストア チームは、UI の作成に必要なコードが大幅に減り、場合によっては 50%削減されることを発見しました。これにより、生産性とコードの保守性が向上します。

その他の事例紹介については、チーム向け Compose を導入するをご覧ください。

実行時のパフォーマンス

このセクションでは、Jetpack Compose の実行時のパフォーマンスに関するトピックを取り上げ、Jetpack Compose とビューシステムのパフォーマンスの比較および測定方法について説明します。

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

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

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

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

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

ビューシステムとの比較

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

すべてがビューの拡張

あらゆるユースケースをサポートするには、画面に描画されるすべての ViewTextViewButtonImageView など)で、メモリ割り当て、明示的な状態トラッキング、さまざまなコールバックが必要になります。さらに、カスタム View オーナーは、明示的なロジックを実装して、データの反復処理などにおける不要な再描画を回避する必要があります。

Jetpack Compose は、いくつかの方法でこの問題に対処します。Compose には、ビューを描画するための明示的な更新可能オブジェクトはありません。UI 要素はシンプルなコンポーズ可能な関数であり、その情報は再現可能な方法でコンポジションに書き込まれます。これにより、上記の機能を必要とするコンポーザブルのみで明示的な状態トラッキング、メモリ割り当て、コールバックが削減され、特定の 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 チームも、Macrobenchmark を使用して、発生する可能性がある回帰を検出しています。たとえば、こちらの遅延列のベンチマークと、回帰をトラッキングしているダッシュボードをご覧ください。

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

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