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

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

APK サイズとビルド時間

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

APK サイズ

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

視聴回数のみ ビューと 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 ミリ秒から 399 ミリ秒に増加しました。これは 100 ミリ秒増加です。この時間は、Compose コンパイラがプロジェクトで定義された Compose コードを変換するために追加のタスクを実行するためです。

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

概要

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

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

実行時のパフォーマンス

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

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

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 アプリの起動時間を短縮してジャンクを減らすためのプロファイル インストール ルールが付属しています。