レイアウト階層の最適化

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

このレッスンでは、Hierarchy ViewerLint を使用してレイアウトを検証、最適化する方法について説明します。

レイアウトの検査

Android SDK Tools には、アプリケーションの実行中にレイアウトを分析できる Hierarchy Viewer というツールが含まれています。このツールを使用すると、レイアウトのパフォーマンスにおけるボトルネックを見つけることができます。

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

たとえば図 1 は、ListView 内のアイテムとして使用されるレイアウトを示しています。このレイアウトの左側には小さなビットマップ画像が、右側には 2 つの縦に並べられたテキスト アイテムが表示されます。特に重要な点は、パフォーマンスを向上させるために、複数回インフレートさせるレイアウト(この例のようなレイアウト)を最適化することです。

図 1. ListView 内のアイテムの概念的なレイアウト

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

図 2. 図 1 のレイアウトのレイアウト階層(ネストされた LinearLayout インスタンスを使用)

レイアウトの見直し

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

図 4. 図 1 のレイアウトのレイアウト階層(RelativeLayout を使用)

このレイアウトはリスト内のすべてのアイテムに使用されるため、わずかに見えてもメリットは数倍になります。

違いのほとんどは、LinearLayout デザインでの layout_weight の使用によるもので、測定速度が遅くなる可能性があります。これは、各レイアウトを適切に使用する方法の一例にすぎず、レイアウトのウェイトを使用する必要があるかどうかを慎重に検討する必要があります。

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

Lint の使用

レイアウト ファイルで lint ツールを実行して、ビュー階層の最適化の可能性を探ることを常におすすめします。 Lint は Layoutopt に代わるツールであり、はるかに優れた機能を備えています。lint ルールの例を次に示します。

  • 複合ドローアブルを使用 - ImageViewTextView を含む LinearLayout は、複合ドローアブルとしてより効率的に処理できます。
  • ルートフレームを結合 - FrameLayout がレイアウトのルートで、背景やパディングなどを指定しない場合、merge タグで置き換えることができます。効率性の向上はわずかです。
  • 不要なリーフ - 子や背景のないレイアウトは、たいていは削除可能です(表示されないため)。これにより、より平坦で効率的なレイアウト階層を実現できます。
  • 不要な親 - 子はあるが兄弟はなく、ScrollView でもルート レイアウトでもなく、背景もないレイアウトを削除し、子を親に直接移動することができます。これにより、より平坦で効率的なレイアウト階層を実現できます。
  • 深いレイアウト - ネスト数が多すぎるレイアウトはパフォーマンスに悪影響を及ぼします。パフォーマンスを向上させるには、RelativeLayoutGridLayout などの平坦なレイアウトの使用を検討します。デフォルトの最大深度は 10 です。

Lint のもう 1 つのメリットは、Android Studio に統合されていることです。Lint は、プログラムをコンパイルするたびに自動的に実行されます。Android Studio では、lint 検査を特定のビルド バリアントのみを対象に実行することも、すべてのビルド バリアントを対象に実行することも可能です。

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

図 5. 検査設定

Lint では、問題の自動的な修正、他者への提案、レビューを目的とした問題のコードへの直接ジャンプが行えます。

このレッスンに関連する情報については、XML レイアウトレイアウト リソースをご覧ください。