Compose のパフォーマンス

Jetpack Compose は、初期設定の状態で優れたパフォーマンスを実現することを目的としています。このページでは、最適なパフォーマンスを実現するアプリを記述、構成する方法について説明するとともに、回避すべきいくつかのパターンを示します。

この記事を読む前に、Compose における考え方で Compose の主要なコンセプトを理解しておくことをおすすめします。

アプリを適切に構成する

アプリのパフォーマンスが低い場合は、構成に問題があることが考えられます。最初のステップとして、次の構成オプションを確認することをおすすめします。

リリースモードでビルドし、R8 を使用する

パフォーマンスの問題が見つかった場合は、アプリをリリースモードで実行してみてください。デバッグモードは、多くの問題を見つけるのに有効ですが、パフォーマンスに多大なコストが発生するため、パフォーマンスの低下につながる可能性のある他のコードの問題を特定するのが困難になることが考えられます。また、R8 コンパイラを使用して、アプリから不要なコードを削除する必要があります。デフォルトでは、リリースモードでのビルドでは、R8 コンパイラが自動的に使用されます。

ベースライン プロファイルを使用する

Compose は、Android プラットフォームの一部ではなく、ライブラリとして配布されています。このアプローチにより、Compose を頻繁に更新し、古い Android バージョンをサポートできます。ただし、Compose をライブラリとして配布するとコストが発生します。Android プラットフォーム コードはすでにコンパイルされ、デバイスにインストールされています。一方、ライブラリは、アプリ起動時に読み込み、機能が必要な場合にジャストインタイムで解釈する必要があります。これにより、アプリの起動時や、ライブラリ機能を初めて使用するときに、アプリの速度が低下する可能性があります。

ベースライン プロファイルを定義することで、パフォーマンスを改善できます。これらのプロファイルは、クリティカル ユーザー ジャーニーに必要なクラスとメソッドを定義し、アプリの APK とともに配布されます。ART は、アプリのインストール中にその重要なコードを事前にコンパイルするため、アプリの起動時に直ちに使用できます。

適切なベースライン プロファイルを定義するのは必ずしも簡単なことではありません。そのため、Compose にはデフォルトのプロファイルが付属しています。特別な作業を行わなくてもそのメリットを享受できる場合があります。ただし、独自のプロファイルを定義すると、アプリのパフォーマンスを実際に改善しないプロファイルが生成される場合があります。プロファイルをテストして、問題が解決したことを確認してください。これを行うには、アプリの Macrobenchmark テストを作成し、ベースライン プロファイルを作成、変更しながらテスト結果を確認するのが適切です。Compose UI の Macrobenchmark テストの作成方法の例については、Macrobenchmark Compose のサンプルをご覧ください。

リリースモード、R8、ベースライン プロファイルの効果の詳細については、ブログ投稿「Why should you always test Compose performance in release?」をご覧ください。

3 つの Compose フェーズがパフォーマンスに与える影響

Jetpack Compose のフェーズで説明したように、Compose がフレームを更新する際、次の 3 つのフェーズを経由します。

  • コンポジション: Compose は表示する内容を決定します。つまり、コンポーズ可能な関数を実行し、UI ツリーをビルドします。
  • レイアウト: Compose は、UI ツリー内の各要素のサイズと配置を決定します。
  • 描画: Compose は、実際に個別の UI 要素をレンダリングします。

Compose は、必要ない場合にこれらのフェーズのいずれかをインテリジェントにスキップできます。たとえば、1 つのグラフィック要素が、同じサイズの 2 つのアイコン間で入れ替わるとします。その要素はサイズが変更されず、UI ツリーの要素が追加または削除されないため、Compose はコンポジション フェーズとレイアウト フェーズをスキップして、その 1 つの要素を再描画できます。

ただし、コーディング上の誤りがあると、Compose が安全にスキップできるフェーズを判別するのが難しくなる場合があります。疑問がある場合、Compose は最終的に 3 つのフェーズすべてを実行するため、UI が必要以上に低速になる可能性があります。そのため、パフォーマンスに関するおすすめの方法の多くは、Compose が実施する必要がないフェーズをスキップできるようにすることに重点を置いています。

一般的にパフォーマンスを改善する原則はいくつかあります。

まず、可能な限り、コンポーズ可能な関数の外部に計算を移動してください。UI が変更されるたびに、コンポーズ可能な関数の再実行が必要になる場合があります。コンポーザブルに追加したコードは、アニメーションのすべてのフレームごとに再実行される可能性があります。そのため、コンポーザブルのコードは、UI のビルドに実際に必要なコードのみに制限する必要があります。

次に、状態の読み取りを可能な限り延期します。状態の読み取りを子コンポーザブルまたは後のフェーズに移動することで、再コンポーズを最小限に抑えるか、コンポジション フェーズを完全にスキップできます。これを行うには、頻繁に変化する状態の場合は、状態値の代わりにラムダ関数を渡し、頻繁に変化する状態を渡すときにラムダベースの修飾子を優先します。この手法の例については、可能な限り読み取りを延期するをご覧ください。