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

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

Compose を Sunflower に初めて追加したとき、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 などの未使用のビュー依存関係が削除されたためです。

ビルド時間

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

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

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

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

概要

Compose を導入すると、アプリの APK サイズが実質的に増加し、Compose コードのコンパイル プロセスによりアプリのビルド時間のパフォーマンスも向上します。ただし、これらのトレードオフは、特に Compose の導入によるデベロッパーの生産性の向上について、Compose のメリットと比較検討する必要があります。たとえば、Google Play ストア チームは、UI の記述に必要なコードが大幅に削減され、最大で 50%削減されることがわかり、コードの生産性とメンテナンス性が向上しました。

その他の事例については、Compose for Teams を導入するをご覧ください。

実行時のパフォーマンス

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

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

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

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

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

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

ビューシステムとの比較

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

すべてがビューの拡張

あらゆるユースケースをサポートするには、画面に描画されるすべての ViewTextViewButtonImageView など)で、メモリ割り当て、明示的な状態トラッキング、さまざまなコールバックが必要になります。さらに、カスタム 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 チームも、Macrobenchmark を使用して、発生する可能性がある回帰を検出しています。たとえば、こちらの遅延列のベンチマークと、回帰をトラッキングしているダッシュボードをご覧ください。

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

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