レイアウト階層を最適化する

Compose を試す
Jetpack Compose は Android で推奨される UI ツールキットです。Compose でレイアウトを操作する方法を学習します。

基本的なレイアウト構造を使用すると最も効率的なレイアウトになるという誤解はよくあります。ただし、アプリに追加するウィジェットとレイアウトにはそれぞれ、初期化、レイアウト、描画が必要です。たとえば、LinearLayout のネストされたインスタンスを使用すると、ビュー階層が深すぎる可能性があります。さらに、layout_weight パラメータを使用する LinearLayout の複数のインスタンスをネストすると、それぞれの子を 2 回測定する必要があるため、特にコストが高くなる可能性があります。これは、レイアウトが繰り返しインフレートされる場合(RecyclerView で使用される場合など)に特に重要です。

このドキュメントでは、Layout Inspectorlint を使用してレイアウトを検証し、最適化する方法について説明します。

レイアウトの検査

Android SDK Tools には Layout Inspector ツールが含まれています。このツールを使用すると、アプリの実行中にレイアウトを分析できます。このツールを使用すると、レイアウト パフォーマンスの非効率性を検出できます。

Layout Inspector を使用すると、接続されたデバイスまたはエミュレータで実行中のプロセスを選択して、レイアウト ツリーを表示できます。各ブロックの信号は、測定、レイアウト、描画のパフォーマンスを示し、潜在的な問題の特定に役立ちます。

たとえば図 1 は、RecyclerView 内のアイテムとして使用されるレイアウトを示しています。このレイアウトでは、左側に小さなビットマップ画像、右側に 2 つの積み重ねられたテキスト アイテムが表示されます。このような複数回インフレートされるレイアウトは、パフォーマンス上のメリットが倍増するため、最適化することが特に重要です。

リスト内の 1 つのアイテム(1 つの画像と 2 つの縦方向に並んだテキスト)を示す画像
図 1. RecyclerView 内のアイテムの概念レイアウト。

Layout Inspector には、使用可能なデバイスと実行中のコンポーネントのリストが表示されます。[Windows] タブからコンポーネントを選択し、[Layout Inspector] をクリックして、選択したコンポーネントのレイアウト階層を表示します。たとえば、図 2 は、図 1 で示したリストアイテムのレイアウトを示しています。

Layout Inspector と LinearLayout 合成を示す画像
図 2. 図 1 のレイアウトのレイアウト階層(ネストされた LinearLayout インスタンスを使用)。

レイアウトの見直し

LinearLayout がネストされているため、上記のレイアウトのパフォーマンスが低下するため、レイアウトをフラット化する(つまり、レイアウトを狭く深くするのではなく、浅く広くする)ことでパフォーマンスが向上する可能性があります。ConstraintLayout をルートノードとして使用することで、このようなレイアウトが可能になります。ConstraintLayout を使用するようにこのデザインを変換すると、レイアウトは次の 2 レベルの階層になります。

    <androidx.constraintlayout.widget.ConstraintLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:id="@+id/root"
      android:layout_width="match_parent"
      android:layout_height="52dp"
      android:background="#e4e6e4"
      android:padding="4dp">

      <ImageView
          android:id="@+id/image"
          android:layout_width="48dp"
          android:layout_height="48dp"
          android:background="#5c5c74"
          android:contentDescription="An example box"
          app:layout_constraintBottom_toBottomOf="parent"
          app:layout_constraintStart_toStartOf="parent"
          app:layout_constraintTop_toTopOf="parent" />

      <TextView
          android:id="@+id/title"
          android:layout_width="0dp"
          android:layout_height="0dp"
          android:layout_marginStart="4dp"
          android:background="#745c74"
          app:layout_constraintBottom_toTopOf="@+id/subtitle"
          app:layout_constraintEnd_toEndOf="parent"
          app:layout_constraintStart_toEndOf="@id/image"
          app:layout_constraintTop_toTopOf="parent" />

      <TextView
          android:id="@+id/subtitle"
          android:layout_width="0dp"
          android:layout_height="0dp"
          android:background="#7e8d6e"
          app:layout_constraintBottom_toBottomOf="parent"
          app:layout_constraintEnd_toEndOf="parent"
          app:layout_constraintStart_toStartOf="@id/title"
          app:layout_constraintTop_toBottomOf="@+id/title" />
  </androidx.constraintlayout.widget.ConstraintLayout>
    

新しいレイアウトの検査は次のようになります。

3D Layout Inspector を示す画像
図 3. Layout Inspector の 3D モード。

このレイアウトはリスト内のすべてのアイテムに使用されるため、このレイアウトのメリットは倍増します。

違いのほとんどは、LinearLayout 設計で layout_weight を使用しているため、測定が遅くなる可能性があります。これは、各レイアウトの適切な使用方法の一例です。レイアウト ウェイトを使用する必要があるかどうかについては、慎重に検討してください。

一部の複雑なレイアウトでは、同じ UI 要素を複数回測定する労力が無駄になる可能性があります。この現象を二重課税といいます。二重負荷とその回避方法の詳細については、パフォーマンスとビュー階層をご覧ください。

lint の使用

レイアウト ファイルに対して lint ツールを実行して、ビュー階層の最適化の可能性を検索することをおすすめします。lint は Layoutopt ツールに代わるもので、機能が向上しています。以下に、lint ルールの例を示します。

  • 複合ドローアブルを使用します。ImageViewTextView を含む LinearLayout は、複合ドローアブルとしてより効率的に処理できます。
  • ルートフレームをマージします。レイアウトのルートが背景やパディングを備えていない FrameLayout である場合、差し込みタグに置き換えると、効率性が向上します。
  • 役に立たない葉は取り除く。子や背景がないレイアウトは非表示になるため、そのレイアウトを削除することで、よりフラットで効率的なレイアウト階層を実現できます。
  • 役に立たない親を削除する。兄弟要素がなく、ScrollView でもルート レイアウトでもなく、背景のない子があるレイアウトは削除できます。また、子ビューを親に直接移動して、よりフラットで効率的なレイアウト階層にすることもできます。
  • 深いレイアウトは避ける。ネストが多すぎるレイアウトはパフォーマンスに悪影響を及ぼします。パフォーマンスを改善するには、ConstraintLayout などのよりフラットなレイアウトを使用することを検討してください。lint チェックのデフォルトの最大深度は 10 です。

lint ツールのもう一つのメリットは、Android Studio への統合です。lint は、プログラムをコンパイルするたびに自動的に実行されます。Android Studio では、特定のビルド バリアントまたはすべてのビルド バリアントに対して lint インスペクションを実行することもできます。

また、[File] > [Settings] > [Project Settings] オプションを使用して、Android Studio 内で検査プロファイルを管理し、検査を構成することもできます。[Inspection Configuration] ページに、サポートされている検査が表示されます。

Android Studio の [検査] メニューを示す画像
図 4. 検査構成ページ。

lint は、一部の問題を自動的に修正し、他の問題への提案を行い、レビューのために問題のコードに直接ジャンプします。

詳細については、レイアウトレイアウト リソースをご覧ください。