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

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

APK サイズとビルド時間

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

APK サイズ

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

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

Compose を Sunflower に初めて追加したとき、APK のサイズは 2,252 KB から 3,034 KB に増えました。これは 782 KB の増加です。生成された APK は、View と Compose が混在する UI ビルドで構成されていました。Sunflower に別の依存関係が追加されたため、この増加は予想どおりです。

逆に、Sunflower を Compose のみのアプリに移行すると、APK サイズは 3,034 KB から 2,966 KB に減少しました。これは 68 KB 減少しています。この減少は、未使用の View 依存関係(AppCompatConstraintLayout など)が削除されたためです。

ビルド時間

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

gradle-profiler --benchmark --project-dir . :app:assembleDebug
視聴回数のみ ビューと 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 と View システムのパフォーマンスを比較して、そのパフォーマンスを測定する方法を理解できるようにします。

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

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

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

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

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

ビューシステムとの比較

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

すべてがビューの拡張

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

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

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

複数のレイアウトパス

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

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

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

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

ベンチマーク作成

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