オンデマンドでビューを読み込む

レイアウトによっては、ほとんど使用されない複雑なビューが必要になる場合があります。アイテムの詳細、進行状況インジケーター、元に戻すメッセージのいずれであっても、必要なときにのみビューを読み込むことで、メモリ使用量を削減し、レンダリングを高速化できます。

複雑でほとんど使用されないビューに ViewStub を定義することで、今後アプリで必要とする複雑なビューがある場合に、リソースの読み込みを遅らせることができます。

ViewStub を定義する

ディメンションのない軽量なビューである ViewStub は、描画を行わないか、またはレイアウトに関与しません。そのため、インフレートしてビュー階層に残すリソースはごくわずかです。各 ViewStub には android:layout 属性が含まれ、インフレートするレイアウトを指定します。

アプリのユーザー ジャーニーの後半で読み込むレイアウトがあるとします。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:src="@drawable/logo"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</FrameLayout>

読み込みを延期するには、次の ViewStub を使用します。表示または読み込みを行うには、参照レイアウトを表示する必要があります。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ViewStub
    android:id="@+id/stub_import"
    android:inflatedId="@+id/panel_import"
    android:layout="@layout/heavy_layout_we_want_to_postpone"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom" />
</FrameLayout>

ViewStub レイアウトを読み込む

前のセクションのコード スニペットは、図 1 のようになります。

空白画面の画像
図 1. 画面の初期状態: ViewStub が重いレイアウトを非表示にしている。

ViewStub で指定されたレイアウトを読み込む場合は、setVisibility(View.VISIBLE) を呼び出して表示するように設定するか、inflate() を呼び出します。

次のコード スニペットは、読み込みの延期をシミュレートします。ActivityonCreate() で画面が通常どおりに読み込まれ、heavy_layout_we_want_to_postpone レイアウトが表示されます。

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_old_xml)

  Handler(Looper.getMainLooper())
      .postDelayed({
          findViewById<View>(R.id.stub_import).visibility = View.VISIBLE
          
          // Or val importPanel: View = findViewById<ViewStub>(R.id.stub_import).inflate()
      }, 2000)
}

Java

@Override
void onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_old_xml);

  Handler(Looper.getMainLooper())
      .postDelayed({
          findViewById<View>(R.id.stub_import).visibility = View.VISIBLE
          
          // Or val importPanel: View = findViewById<ViewStub>(R.id.stub_import).inflate()
      }, 2000);
}
図 2. 重いレイアウトが表示されています。

可視化またはインフレートされると、ViewStub 要素はビュー階層の一部ではなくなり、インフレートされたレイアウトに置き換えられます。このレイアウトのルートビューの ID は ViewStubandroid:inflatedId 属性で指定します。ViewStub に指定された ID android:id は、ViewStub レイアウトが可視化またはインフレートされるまでのみ有効です。

このトピックの詳細については、ブログ投稿 Optimize with stubs をご覧ください。