LiveData の概要  Android Jetpack の一部

LiveData は監視可能なデータホルダー クラスです。通常の監視とは異なり、LiveData はライフサイクルに応じた監視が可能です。つまり、アクティビティ、フラグメント、サービスなどの他のアプリ コンポーネントのライフサイクルが考慮されます。このため、LiveData は、ライフサイクルの状態がアクティブなアプリ コンポーネント オブザーバーのみを更新します。

オブザーバー(Observer クラスで表されます)のライフサイクルの状態が STARTED または RESUMED の場合、LiveData はそのオブザーバーをアクティブな状態であると見なします。LiveData は更新に関する情報をアクティブなオブザーバーにのみ通知します。LiveData オブジェクトを監視するために登録されている非アクティブなオブザーバーには、変更に関する通知は行われません。

オブザーバーは、LifecycleOwner インターフェースを実装するオブジェクトとペアで登録できます。このようにペアリングすることで、対応する Lifecycle オブジェクトの状態が DESTROYED に変わったときにオブザーバーを削除できます。特に、アクティビティとフラグメントでこの手法を利用すると、LiveData オブジェクトを安全に監視でき、リークについて心配する必要がなくなるため非常に有用です。アクティビティとフラグメントは、そのライフサイクルが破棄されるとすぐに登録解除されます。

LiveData の使用方法について詳しくは、LiveData オブジェクトを操作するをご覧ください。

LiveData を使用するメリット

LiveData を使用するメリットには次のようなものがあります。

UI をデータの状態と一致させることができる
LiveData はオブザーバーのパターンに従います。LiveData は、ライフサイクルの状態が変化したときに Observer オブジェクトに通知します。Observer オブジェクト内の UI を更新するコードは統合できます。オブザーバーは、アプリのデータが変更されるたびに UI を更新するのではなく、変化が生じるたびに UI を更新できます。
メモリリークが発生しない
オブザーバーは Lifecycle オブジェクトにバインドされており、関連付けられているライフサイクルが破棄されたときに自身のクリーンアップを行います。
停止されたアクティビティに起因するクラッシュが発生しない
オブザーバーのライフサイクルがアクティブでない場合(アクティビティがバックスタック内にある場合など)、オブザーバーは LiveData イベントを受け取りません。
手動によるライフサイクル処理が行われない
UI コンポーネントは関連データを監視するだけで、監視の停止や再開は行いませんが、LiveData はそのすべてを自動的に管理します。これは、LiveData が監視を行いながら、関連するライフサイクルの状態の変化を認識するためです。
データが常に最新
ライフサイクルが非アクティブになると、各コンポーネントは再びアクティブになったときに最新のデータを受け取ります。たとえば、バックグラウンドのアクティビティは、フォアグラウンドに戻った直後に最新のデータを受け取ります。
適切な設定の変更
アクティビティやフラグメントは、設定の変更(デバイスの回転など)によって再作成されると、使用可能な最新のデータをすぐに受け取ります。
リソースの共有
シングルトン パターンを使用してシステム サービスをラップすることで、LiveData オブジェクトを拡張できます。これにより、アプリ内でリソースを共有できるようになります。LiveData オブジェクトがシステム サービスに関連付けられると、リソースを必要とするすべてのオブザーバーが LiveData オブジェクトを監視できるようになります。詳しくは、LiveData を拡張するをご覧ください。

LiveData オブジェクトを操作する

LiveData オブジェクトを操作する手順は次のとおりです。

  1. 特定のタイプのデータを保持する LiveData のインスタンスを作成します。これは通常、ViewModel クラス内で行います。
  2. onChanged() メソッドを定義する Observer オブジェクトを作成します。このオブジェクトは、LiveData オブジェクトが保持するデータが変更されたときに行われる処理を管理します。通常は、UI コントローラ(アクティビティやフラグメントなど)内に Observer オブジェクトを作成します。
  3. observe() メソッドを使用して、Observer オブジェクトを LiveData オブジェクトにアタッチします。observe() メソッドは LifecycleOwner オブジェクトを取得します。これにより、Observer オブジェクトが LiveData オブジェクトに登録され、変更が通知されるようになります。通常は、UI コントローラ(アクティビティやフラグメントなど)内の Observer オブジェクトをアタッチします。

LiveData オブジェクトに格納されている値を更新する場合、アタッチされている LifecycleOwner がアクティブな状態である限り、登録済みのすべてのオブザーバーがトリガーされます。

LiveData を使用すると、UI コントローラのオブザーバーが最新情報を受け取ることができます。LiveData オブジェクトで保持されているデータが変更されると、それに応じて UI が自動的に更新されます。

LiveData オブジェクトを作成する

LiveData は、任意のデータ(List などの Collections を実装するオブジェクトを含む)とともに使用できるラッパーです。通常、LiveData オブジェクトは ViewModel オブジェクトに格納され、次の例に示すように getter メソッドを介してアクセスします。

Kotlin

    class NameViewModel : ViewModel() {

        // Create a LiveData with a String
        val currentName: MutableLiveData<String> by lazy {
            MutableLiveData<String>()
        }

        // Rest of the ViewModel...
    }
    

Java

    public class NameViewModel extends ViewModel {

    // Create a LiveData with a String
    private MutableLiveData<String> currentName;

        public MutableLiveData<String> getCurrentName() {
            if (currentName == null) {
                currentName = new MutableLiveData<String>();
            }
            return currentName;
        }

    // Rest of the ViewModel...
    }
    

最初の段階では、LiveData オブジェクトのデータは設定されていません。

ViewModel クラスのメリットと使用方法について詳しくは、ViewModel ガイドをご覧ください。

LiveData オブジェクトを監視する

ほとんどの場合、アプリ コンポーネントの onCreate() メソッドが LiveData オブジェクトの監視を開始するのに適した場所になっています。理由は以下のとおりです。

  • アクティビティやフラグメントの onResume() メソッドからの冗長な呼び出しをシステムが行わないようにすることができるため。
  • アクティビティやフラグメントがアクティブになり次第、そのデータを表示できるため。アプリ コンポーネントは STARTED の状態になるとすぐに、監視対象の LiveData オブジェクトから最新の値を受け取ります。これは、監視対象の LiveData オブジェクトが設定されている場合にのみ行われます。

LiveData は通常、データが変更された場合にのみ最新データを配信します(対象はアクティブなオブザーバーのみ)。オブザーバーは、非アクティブな状態からアクティブな状態に変わったときにも最新データを受け取りますが、これは例外的な動作です。さらに、オブザーバーが次に非アクティブな状態からアクティブな状態に変わったときは、前回アクティブになったときから変更された値がある場合にのみ最新データを受け取ります。

次のサンプルコードは、LiveData オブジェクトの監視を開始する方法を示しています。

Kotlin

    class NameActivity : AppCompatActivity() {

        private lateinit var model: NameViewModel

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)

            // Other code to setup the activity...

            // Get the ViewModel.
            model = ViewModelProviders.of(this).get(NameViewModel::class.java)

            // Create the observer which updates the UI.
            val nameObserver = Observer<String> { newName ->
                // Update the UI, in this case, a TextView.
                nameTextView.text = newName
            }

            // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
            model.currentName.observe(this, nameObserver)
        }
    }
    

Java

    public class NameActivity extends AppCompatActivity {

        private NameViewModel model;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            // Other code to setup the activity...

            // Get the ViewModel.
            model = ViewModelProviders.of(this).get(NameViewModel.class);

            // Create the observer which updates the UI.
            final Observer<String> nameObserver = new Observer<String>() {
                @Override
                public void onChanged(@Nullable final String newName) {
                    // Update the UI, in this case, a TextView.
                    nameTextView.setText(newName);
                }
            };

            // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
            model.getCurrentName().observe(this, nameObserver);
        }
    }
    

observe() が呼び出され、パラメータとして nameObserver が渡されると、mCurrentName に最新の値が保存されている場合は onChanged() がすぐに呼び出されます。LiveData オブジェクトの mCurrentName に値が設定されていない場合、onChanged() は呼び出されません。

LiveData オブジェクトを更新する

LiveData には、格納されているデータを更新するための公開メソッドはありません。LiveData オブジェクトに格納されている値を編集する必要がある場合は、MutableLiveData クラスで公開されている setValue(T) メソッドと postValue(T) メソッドを使用する必要があります。通常、MutableLiveDataViewModel で使用され、その場合、ViewModel は不変の LiveData オブジェクトのみをオブザーバーに公開します。

オブザーバーの関係をセットアップすると、次の例に示すように、LiveData オブジェクトの値を更新できるようになります。これにより、ユーザーがボタンをタップしたときにすべてのオブザーバーがトリガーされます。

Kotlin

    button.setOnClickListener {
        val anotherName = "John Doe"
        model.currentName.setValue(anotherName)
    }
    

Java

    button.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            String anotherName = "John Doe";
            model.getCurrentName().setValue(anotherName);
        }
    });
    

この例の setValue(T) を呼び出すと、値 John Doe が指定された onChanged() メソッドがオブザーバーによって呼び出されます。これはボタン押下の例ですが、ネットワーク リクエストに対する応答や、データベースの読み込み完了など、さまざまな理由で setValue() または postValue() を呼び出して mName を更新できます。いずれの場合でも、setValue() または postValue() を呼び出すことによってオブザーバーがトリガーされ、UI が更新されます。

LiveData と Room を併用する

Room 永続ライブラリは、LiveData オブジェクトを返す監視可能なクエリをサポートしています。監視可能なクエリは、データベース アクセス オブジェクト(DAO)の一部として記述されます。

データベースが更新されると、LiveData オブジェクトの更新に必要なすべてのコードが Room によって生成されます。生成されたコードにより、クエリが必要に応じてバックグラウンドのスレッドで非同期実行されます。このパターンは、データベースに格納されているデータと同期したデータが常に UI に表示されるようにするうえで役立ちます。Room と DAO について詳しくは、Room 永続ライブラリ ガイドをご覧ください。

LiveData でコルーチンを使用する

LiveData には、Kotlin コルーチンのサポートが含まれています。詳しくは、Android アーキテクチャ コンポーネントで Kotlin コルーチンを使用するをご覧ください。

LiveData を拡張する

オブザーバーのライフサイクルの状態が STARTED または RESUMED の場合、LiveData はオブザーバーがアクティブな状態であると見なします。次のサンプルコードは、LiveData クラスを拡張する方法を示しています。

Kotlin

    class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
        private val stockManager = StockManager(symbol)

        private val listener = { price: BigDecimal ->
            value = price
        }

        override fun onActive() {
            stockManager.requestPriceUpdates(listener)
        }

        override fun onInactive() {
            stockManager.removeUpdates(listener)
        }
    }
    

Java

    public class StockLiveData extends LiveData<BigDecimal> {
        private StockManager stockManager;

        private SimplePriceListener listener = new SimplePriceListener() {
            @Override
            public void onPriceChanged(BigDecimal price) {
                setValue(price);
            }
        };

        public StockLiveData(String symbol) {
            stockManager = new StockManager(symbol);
        }

        @Override
        protected void onActive() {
            stockManager.requestPriceUpdates(listener);
        }

        @Override
        protected void onInactive() {
            stockManager.removeUpdates(listener);
        }
    }
    

この例の価格リスナーの実装には、以下の重要なメソッドが含まれています。

  • onActive() メソッドは、LiveData オブジェクトにアクティブなオブザーバーが含まれている場合に呼び出されます。つまり、株価の最新情報の監視はこのメソッドから開始する必要があります。
  • onInactive() メソッドは、LiveData オブジェクトにアクティブなオブザーバーが含まれていない場合に呼び出されます。リッスンしているオブザーバーがないため、StockManager サービスへの接続を維持する理由はありません。
  • setValue(T) メソッドは、LiveData インスタンスの値を更新し、変更に関する情報をアクティブなオブザーバーに通知します。

StockLiveData クラスは次のように使用することができます。

Kotlin

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        val myPriceListener: LiveData<BigDecimal> = ...
        myPriceListener.observe(this, Observer<BigDecimal> { price: BigDecimal? ->
            // Update the UI.
        })
    }
    

Java

    public class MyFragment extends Fragment {
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            LiveData<BigDecimal> myPriceListener = ...;
            myPriceListener.observe(this, price -> {
                // Update the UI.
            });
        }
    }
    

observe() メソッドは、最初の引数として LifecycleOwner のインスタンスであるフラグメントを渡します。こうすることで、このオブザーバーがオーナーに関連付けられている Lifecycle オブジェクトにバインドされていることが示されます。つまり、以下のようになります。

  • Lifecycle オブジェクトがアクティブな状態でない場合、値が変更されてもオブザーバーは呼び出されません。
  • Lifecycle オブジェクトが破棄された後、オブザーバーは自動的に削除されます。

LiveData オブジェクトがライフサイクル対応だと、複数のアクティビティ、フラグメント、サービスの間でそれを共有できます。簡単な例として、次のように LiveData クラスをシングルトンとして実装することができます。

Kotlin

    class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
        private val stockManager: StockManager = StockManager(symbol)

        private val listener = { price: BigDecimal ->
            value = price
        }

        override fun onActive() {
            stockManager.requestPriceUpdates(listener)
        }

        override fun onInactive() {
            stockManager.removeUpdates(listener)
        }

        companion object {
            private lateinit var sInstance: StockLiveData

            @MainThread
            fun get(symbol: String): StockLiveData {
                sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
                return sInstance
            }
        }
    }
    

Java

    public class StockLiveData extends LiveData<BigDecimal> {
        private static StockLiveData sInstance;
        private StockManager stockManager;

        private SimplePriceListener listener = new SimplePriceListener() {
            @Override
            public void onPriceChanged(BigDecimal price) {
                setValue(price);
            }
        };

        @MainThread
        public static StockLiveData get(String symbol) {
            if (sInstance == null) {
                sInstance = new StockLiveData(symbol);
            }
            return sInstance;
        }

        private StockLiveData(String symbol) {
            stockManager = new StockManager(symbol);
        }

        @Override
        protected void onActive() {
            stockManager.requestPriceUpdates(listener);
        }

        @Override
        protected void onInactive() {
            stockManager.removeUpdates(listener);
        }
    }
    

また、次のようにフラグメント内で使用することもできます。

Kotlin

    class MyFragment : Fragment() {

        override fun onActivityCreated(savedInstanceState: Bundle?) {
            StockLiveData.get(symbol).observe(this, Observer<BigDecimal> { price: BigDecimal? ->
                // Update the UI.
            })

        }
    

Java

    public class MyFragment extends Fragment {
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            StockLiveData.get(symbol).observe(this, price -> {
                // Update the UI.
            });
        }
    }
    

MyPriceListener インスタンスは複数のフラグメントとアクティビティで監視できます。そのうちの 1 つ以上が参照可能でアクティブな場合にのみ、LiveData はシステム サービスに接続します。

LiveData を変換する

LiveData オブジェクトに格納されている値の変更は、オブザーバーにディスパッチする前に行うことをおすすめします。そうしないと、別のインスタンスの値に基づいて異なる LiveData インスタンスを返さなければならなくなることがあります。Lifecycle パッケージが提供する Transformations クラスには、このようなシナリオをサポートするヘルパー メソッドが含まれています。

Transformations.map()
LiveData オブジェクトに保存されている値に関数を適用し、結果を下流に伝えます。

Kotlin

    val userLiveData: LiveData<User> = UserLiveData()
    val userName: LiveData<String> = Transformations.map(userLiveData) {
        user -> "${user.name} ${user.lastName}"
    }
    

Java

    LiveData<User> userLiveData = ...;
    LiveData<String> userName = Transformations.map(userLiveData, user -> {
        user.name + " " + user.lastName
    });
    
Transformations.switchMap()
map() と同様に、LiveData オブジェクトに格納されている値に関数を適用し、結果のラップを解除して下流にディスパッチします。switchMap() に渡された関数は、次の例に示すように、LiveData オブジェクトを返す必要があります。

Kotlin

    private fun getUser(id: String): LiveData<User> {
      ...
    }
    val userId: LiveData<String> = ...
    val user = Transformations.switchMap(userId) { id -> getUser(id) }
    

Java

    private LiveData<User> getUser(String id) {
      ...;
    }

    LiveData<String> userId = ...;
    LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
    

変換メソッドを使用すると、オブザーバーのライフサイクル全体を通して情報を伝えることができます。返された LiveData オブジェクトをオブザーバーが監視している場合を除き、変換は計算されません。変換は必要に応じて計算されるため、ライフサイクル関連の動作は暗黙的に伝えられます。追加の明示的な呼び出しや依存関係は必要ありません。

ViewModel オブジェクト内に Lifecycle オブジェクトが必要だと思われる場合、ソリューションとしてはおそらく変換が適しています。たとえば、住所を受け取ってその住所の郵便番号を返す UI コンポーネントがあるとします。このコンポーネントには、次のサンプルコードに示すように、単純な ViewModel を実装できます。

Kotlin

    class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() {

        private fun getPostalCode(address: String): LiveData<String> {
            // DON'T DO THIS
            return repository.getPostCode(address)
        }
    }
    

Java

    class MyViewModel extends ViewModel {
        private final PostalCodeRepository repository;
        public MyViewModel(PostalCodeRepository repository) {
           this.repository = repository;
        }

        private LiveData<String> getPostalCode(String address) {
           // DON'T DO THIS
           return repository.getPostCode(address);
        }
    }
    

UI コンポーネントは、以前の LiveData オブジェクトへの登録を解除して、getPostalCode() を呼び出すたびに新しいインスタンスに登録する必要があります。また、UI コンポーネントを再作成する場合は、以前の呼び出しの結果を使用するのではなく、repository.getPostCode() メソッドの呼び出しをもう一度トリガーします。

さらに、次の例に示すように、住所の入力の変換として郵便番号の検索を実装することもできます。

Kotlin

    class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() {
        private val addressInput = MutableLiveData<String>()
        val postalCode: LiveData<String> = Transformations.switchMap(addressInput) {
                address -> repository.getPostCode(address) }

        private fun setInput(address: String) {
            addressInput.value = address
        }
    }
    

Java

    class MyViewModel extends ViewModel {
        private final PostalCodeRepository repository;
        private final MutableLiveData<String> addressInput = new MutableLiveData();
        public final LiveData<String> postalCode =
                Transformations.switchMap(addressInput, (address) -> {
                    return repository.getPostCode(address);
                 });

      public MyViewModel(PostalCodeRepository repository) {
          this.repository = repository
      }

      private void setInput(String address) {
          addressInput.setValue(address);
      }
    }
    

この場合、postalCode フィールドは addressInput の変換として定義されます。アプリのアクティブなオブザーバーが postalCode フィールドに関連付けられている場合、addressInput が変更されるたびに、そのフィールドの値は再計算され、取得されます。

このメカニズムにより、必要に応じてオンデマンドで計算される LiveData オブジェクトを下位レベルのアプリで作成できます。ViewModel オブジェクトでは、LiveData オブジェクトへの参照を簡単に取得でき、それを基盤として変換ルールを定義することができます。

新しい変換を作成する

アプリで役立つ 12 個の特殊な変換が用意されています。ただし、それらの変換はデフォルトでは提供されていません。独自の変換を実装するには、MediatorLiveData クラスを使用します。このクラスは他の LiveData オブジェクトをリッスンし、そのオブジェクトによって生成されたイベントを処理します。MediatorLiveData はその状態を元の LiveData オブジェクトに正しく伝えます。このパターンについて詳しくは、Transformations クラスのリファレンス ドキュメントをご覧ください。

複数の LiveData ソースを統合する

MediatorLiveDataLiveData のサブクラスです。このサブクラスを使用すると、複数の LiveData ソースを統合できます。元の LiveData ソース オブジェクトのいずれかが変更されると、MediatorLiveData オブジェクトのオブザーバーが必ずトリガーされます。

たとえば、ローカル データベースやネットワークから更新可能な LiveData オブジェクトが UI 内にある場合、以下のソースを MediatorLiveData オブジェクトに追加できます。

  • データベースに格納されているデータに関連付けられている LiveData オブジェクト。
  • ネットワークからアクセスされるデータに関連付けられている LiveData オブジェクト。

アクティビティで行う必要があるのは、MediatorLiveData オブジェクトを監視して、両方のソースから最新データを受け取ることだけです。詳しい例については、アプリのアーキテクチャ ガイド付録: ネットワーク ステータスの公開をご覧ください。

その他のリソース

LiveData クラスについて詳しくは、次のリソースをご覧ください。

サンプル

コードラボ

ブログ

動画