基本的なレイアウト構造を使用すると最も効率的なレイアウトになるという誤解はよくあります。ただし、アプリに追加するウィジェットとレイアウトにはそれぞれ、初期化、レイアウト、描画が必要です。たとえば、LinearLayout
のネストされたインスタンスを使用すると、ビュー階層が深すぎる可能性があります。さらに、layout_weight
パラメータを使用する LinearLayout
の複数のインスタンスをネストすると、それぞれの子を 2 回測定する必要があるため、特にコストが高くなる可能性があります。これは、レイアウトが繰り返しインフレートされる場合(RecyclerView
で使用される場合など)に特に重要です。
このドキュメントでは、Layout Inspector と lint を使用してレイアウトを検証し、最適化する方法について説明します。
レイアウトの検査
Android SDK Tools には Layout Inspector ツールが含まれています。このツールを使用すると、アプリの実行中にレイアウトを分析できます。このツールを使用すると、レイアウト パフォーマンスの非効率性を検出できます。
Layout Inspector を使用すると、接続されたデバイスまたはエミュレータで実行中のプロセスを選択して、レイアウト ツリーを表示できます。各ブロックの信号は、測定、レイアウト、描画のパフォーマンスを示し、潜在的な問題の特定に役立ちます。
たとえば図 1 は、RecyclerView
内のアイテムとして使用されるレイアウトを示しています。このレイアウトでは、左側に小さなビットマップ画像、右側に 2 つの積み重ねられたテキスト アイテムが表示されます。このような複数回インフレートされるレイアウトは、パフォーマンス上のメリットが倍増するため、最適化することが特に重要です。
Layout Inspector には、使用可能なデバイスと実行中のコンポーネントのリストが表示されます。[Windows] タブからコンポーネントを選択し、[Layout Inspector] をクリックして、選択したコンポーネントのレイアウト階層を表示します。たとえば、図 2 は、図 1 で示したリストアイテムのレイアウトを示しています。
レイアウトの見直し
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>
新しいレイアウトの検査は次のようになります。
このレイアウトはリスト内のすべてのアイテムに使用されるため、このレイアウトのメリットは倍増します。
違いのほとんどは、LinearLayout
設計で layout_weight
を使用しているため、測定が遅くなる可能性があります。これは、各レイアウトの適切な使用方法の一例です。レイアウト ウェイトを使用する必要があるかどうかについては、慎重に検討してください。
一部の複雑なレイアウトでは、同じ UI 要素を複数回測定する労力が無駄になる可能性があります。この現象を二重課税といいます。二重負荷とその回避方法の詳細については、パフォーマンスとビュー階層をご覧ください。
lint の使用
レイアウト ファイルに対して lint ツールを実行して、ビュー階層の最適化の可能性を検索することをおすすめします。lint は Layoutopt ツールに代わるもので、機能が向上しています。以下に、lint ルールの例を示します。
-
複合ドローアブルを使用します。
ImageView
とTextView
を含むLinearLayout
は、複合ドローアブルとしてより効率的に処理できます。 -
ルートフレームをマージします。レイアウトのルートが背景やパディングを備えていない
FrameLayout
である場合、差し込みタグに置き換えると、効率性が向上します。 - 役に立たない葉は取り除く。子や背景がないレイアウトは非表示になるため、そのレイアウトを削除することで、よりフラットで効率的なレイアウト階層を実現できます。
-
役に立たない親を削除する。兄弟要素がなく、
ScrollView
でもルート レイアウトでもなく、背景のない子があるレイアウトは削除できます。また、子ビューを親に直接移動して、よりフラットで効率的なレイアウト階層にすることもできます。 -
深いレイアウトは避ける。ネストが多すぎるレイアウトはパフォーマンスに悪影響を及ぼします。パフォーマンスを改善するには、
ConstraintLayout
などのよりフラットなレイアウトを使用することを検討してください。lint チェックのデフォルトの最大深度は 10 です。
lint ツールのもう一つのメリットは、Android Studio への統合です。lint は、プログラムをコンパイルするたびに自動的に実行されます。Android Studio では、特定のビルド バリアントまたはすべてのビルド バリアントに対して lint インスペクションを実行することもできます。
また、[File] > [Settings] > [Project Settings] オプションを使用して、Android Studio 内で検査プロファイルを管理し、検査を構成することもできます。[Inspection Configuration] ページに、サポートされている検査が表示されます。
lint は、一部の問題を自動的に修正し、他の問題への提案を行い、レビューのために問題のコードに直接ジャンプします。
詳細については、レイアウトとレイアウト リソースをご覧ください。