【Android Architecture Components】LiveData 和訳

# 注意
[LiveData](https://developer.android.com/topic/libraries/architecture/livedata.html)の和訳になります。
わかりづらい表現を意訳したり、回りくどいところを端折ったりしています。
和訳に自信がないところもあるため、間違いを見つけた場合は指摘してください。


・・・・・

[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)はライフサイクルを意識した監視可能なデータホルダークラスです。
通常の観測とは異なり、[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)は[Lifecycle](https://developer.android.com/reference/android/arch/lifecycle/Lifecycle.html)によって、観測するアプリケーションコンポーネントのライフサイクルを考慮します。

>注：[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)をプロジェクトにインポートする方法については[Adding Components to your Project
](https://developer.android.com/topic/libraries/architecture/adding-components.html)を参照してください。

[Observer](https://developer.android.com/reference/android/arch/lifecycle/Observer)の[Lifecycle](https://developer.android.com/reference/android/arch/lifecycle/Lifecycle.html)が```STARTED```か```RESUMED```の状態の場合、[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)は[Observer](https://developer.android.com/reference/java/util/Observer.html)をアクティブ状態とします。

```java
public class LocationLiveData extends LiveData<Location> {
    private LocationManager locationManager;

    private SimpleLocationListener listener = new SimpleLocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            setValue(location);
        }
    };

    public LocationLiveData(Context context) {
        locationManager = (LocationManager) context.getSystemService(
                Context.LOCATION_SERVICE);
    }

    @Override
    protected void onActive() {
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
    }

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

[Location](https://developer.android.com/reference/android/location/Location.html)リスナーの実装で３つの重要な箇所があります。

### onActive()
このメソッドは[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)にアクティブな[Observer](https://developer.android.com/reference/java/util/Observer.html)がある場合に呼び出されます。
これは、デバイスからのロケーション更新を観測する必要があることを意味します。

### onInactive()
このメソッドは[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)にアクティブな[Observer](https://developer.android.com/reference/java/util/Observer.html)が無い場合に呼び出されます。
アクティブな[Observer](https://developer.android.com/reference/java/util/Observer.html)が無いので、[LocationManager](https://developer.android.com/reference/android/location/LocationManager.html)に接続しておく必要はありません。無駄にバッテリーのを消費するだけです。

### setValue()
このメソッドを呼び出すと、[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)インスタンスの値が更新され、アクティブな[Observer](https://developer.android.com/reference/java/util/Observer.html)に変更を通知します。


この新しい```LocationLiveData```をこのように使用できます。

```java
public class MyFragment extends LifecycleFragment {
    public void onActivityCreated (Bundle savedInstanceState) {
        LiveData<Location> myLocationListener = ...;
        Util.checkUserStatus(result -> {
            if (result) {
                myLocationListener.addObserver(this, location -> {
                    // update UI
                });
            }
        });
    }
}
```

```addObserver()``` の第一引数に[LifecycleOwner](https://developer.android.com/reference/android/arch/lifecycle/LifecycleOwner.html)を渡しています。
これは、オブザーバが[Lifecycle](https://developer.android.com/reference/android/arch/lifecycle/Lifecycle.html)に紐づけられることを意味しています。
これによって、

・[Lifecycle](https://developer.android.com/reference/android/arch/lifecycle/Lifecycle.html)がアクティブな状態（```STARTED```または```RESUMED```）でない場合、オブザーバは値の更新があったとしても呼び出されません。

・[Lifecycle](https://developer.android.com/reference/android/arch/lifecycle/Lifecycle.html)が破棄された場合、自動的にオブザーバも解除されます。

[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)がライフサイクルに対応していることで、複数のActivity、Fragmentなどの間でデータの共有が可能になります。

サンプルをシンプルにするため、シングルトンにしています。

```java
public class LocationLiveData extends LiveData<Location> {
    private static LocationLiveData sInstance;
    private LocationManager locationManager;

    @MainThread
    public static LocationLiveData get(Context context) {
        if (sInstance == null) {
            sInstance = new LocationLiveData(context.getApplicationContext());
        }
        return sInstance;
    }

    private SimpleLocationListener listener = new SimpleLocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            setValue(location);
        }
    };

    private LocationLiveData(Context context) {
        locationManager = (LocationManager) context.getSystemService(
                Context.LOCATION_SERVICE);
    }

    @Override
    protected void onActive() {
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
    }

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

Fragmentで以下のように使用します。

```java
public class MyFragment extends LifecycleFragment {
    public void onActivityCreated (Bundle savedInstanceState) {
        Util.checkUserStatus(result -> {
            if (result) {
                LocationLiveData.get(getActivity()).observe(this, location -> {
                   // update UI
                });
            }
        });
  }
}
```

```MyLocationListener``` インスタンスを複数のActivityやFragmentから観測している場合もあり、
[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)はそれらがアクティブ状態の時だけ接続するようにうまく管理します。

[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)には以下の利点があります。

・ **メモリリークをしない**：[Observer](https://developer.android.com/reference/java/util/Observer.html)が[Lifecycle](https://developer.android.com/reference/android/arch/lifecycle/Lifecycle.html)に紐づくことによって、[Lifecycle](https://developer.android.com/reference/android/arch/lifecycle/Lifecycle.html)が破棄される時に[Observer](https://developer.android.com/reference/java/util/Observer.html)も解除されます。

・ **Activityが非活性になったことによるクラッシュがなくなる**：[Observer](https://developer.android.com/reference/java/util/Observer.html)の[Lifecycle](https://developer.android.com/reference/android/arch/lifecycle/Lifecycle.html)が非活性（Activityがバックスタックにいるなど）である場合、変更イベントを受け付けません。

・ **常に最新のデータ**：ライフサイクルが再び開始された場合（Activityがバックスタックから復帰した場合など）、最新のロケーションデータが受信されます。

・ **構成の変更に適切に対処できる**：画面回転などによって構成が変更され、ActivityやFragmentが再生成された場合でも、すぐに最後に有効だった[Location](https://developer.android.com/reference/android/location/Location.html)を使用できます。

・ **リソースの共有**：```MyLocationListener```の単一のインスタンスで、システムサービスに１度だけ接続して、アプリ内のすべてのオブザーバを適切にサポートします。

・ **ライフサイクルのハンドリングから解放される**：```MyFragment```は必要な時にデータを観察するだけで、```MyFragment```が停止状態であることを気にする必要もなく、停止後に観察を開始することもありません。
```MyFragment```自身のライフサイクルを紐づけることによって、[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)はこれを全て自動化しています。

# LiveDataのトランスフォーメーション

オブザーバに通知する前に[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)の値を変更したり、値を元に別の[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)インスタンスに変換して返す必要があるかもしれません。

[android.arch.lifecycle](https://developer.android.com/reference/android/arch/lifecycle/package-summary.html)パッケージはこれらの操作のヘルパーメソッドを含む[Transformations](https://developer.android.com/reference/android/arch/lifecycle/Transformations.html)クラスを提供します。

### [Transformations.map()](https://developer.android.com/reference/android/arch/lifecycle/Transformations.html#map(android.arch.lifecycle.LiveData<X>,%20android.arch.core.util.Function<X, Y>))
[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)に関数を適用し、結果を下流に伝播します。

```java
LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
    user.name + " " + user.lastName
});
```

### [Transformations.switchMap()](https://developer.android.com/reference/android/arch/lifecycle/Transformations.html#switchMap(android.arch.lifecycle.LiveData<X>,%20android.arch.core.util.Function<X,%20android.arch.lifecycle.LiveData<Y>>))
[map()](https://developer.android.com/reference/android/arch/lifecycle/Transformations.html#map(android.arch.lifecycle.LiveData<X>,%20android.arch.core.util.Function<X, Y>))と似ていて、値に関数を適用して別の[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)を生成して下流に結果を伝播します。

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

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

トランスフォーメーションはオブザーバが無効な場合は無駄な処理をしないように、[Lifecycle](https://developer.android.com/reference/android/arch/lifecycle/Lifecycle.html)を引き継ぐので、明示的な呼び出しや依存関係を追加することなく、ライフサイクルに関連した動作を暗黙的に行うことができます。


例えば、ユーザが住所を入力して、その住所の郵便番号を受け取るUIがあるとします。
このUIの純粋な[ViewModel](https://developer.android.com/reference/android/arch/lifecycle/ViewModel.html)はこのようになります。

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

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

>注：原文では```getPostalCode()```が```private```ですが、```public```にしています。

この実装の場合、```getPostalCode()```を呼び出すたびに、前の[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)から登録を解除して、新しい[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)インスタンスで再登録を行う必要があります。
さらに、UIが再生成された場合、前とは別の```repository.getPostCode()```を呼び出します。

上記の実装の代わりに、住所を入力して郵便番号に変換する実装にすることができます。

```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
  }

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

>注：原文では```setInput()```が```private```ですが、```public```にしています。

```postalCode```のインスタンスは変更されないので、```public final```で定義されていることに注目してください。
```postalCode```は```addressInput```のトランスフォーメーションのために定義され、```addressInput```に変更があった時にアクティブなオブザーバが存在する場合、```repository.getPostCode()```が呼び出されます。もし、アクティブなオブザーバが存在しない場合は、オブザーバが追加されるまで処理は実行されません。


# 独自のトランスフォーメーションを作成する

独自のトランスフォーメーションを作成するために[MediatorLiveData](https://developer.android.com/reference/android/arch/lifecycle/MediatorLiveData.html)クラスを使用します。
このクラスは、他の[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)インスタンスを適切にリッスンして、通知されたイベントを処理するために作られました。
[MediatorLiveData](https://developer.android.com/reference/android/arch/lifecycle/MediatorLiveData.html)は[LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)のアクティブ/非アクティブ状態を考慮してに通知します。
詳しくは[Transformations](https://developer.android.com/reference/android/arch/lifecycle/Transformations.html)を参照してください。