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

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

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

レイアウトの検査

Android SDK ツールには、アプリケーションの実行中にレイアウトを分析できる 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 レイアウトレイアウト リソースをご覧ください。