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