Smile Engineering Blog

ジェイエスピーからTipsや技術特集、プロジェクト物語を発信します

【Android】map や switchMap で LiveData を変換する

今回は、map や switchMap で LiveData を変換する方法を解説します。

なお、ここに掲載しているソースコードは以下の環境で動作確認しています。

  • Android Studio Bumblebee | 2021.1.1 Patch 2
  • JDK 11.0.11
  • Android Gradle Plugin 7.1.2
  • Kotlin 1.6.10
  • Gradle 7.4.1
  • androidx.lifecycle 2.4.1

また、実際に LiveData の map や switchMap を使用する際は、以下のようにアプリの build.gradle ファイルに lifecycle-livedata-ktx をインポートしてください。

dependencies {
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
}

map とは?

map は LiveData の拡張関数の 1 つです。

public inline fun <X, Y> LiveData<X>.map(
    crossinline transform: (X) -> Y
): LiveData<Y>

この関数の使い方は、変換したい LiveData に対して変換処理 transform を渡すだけです。そうすると、変換元の LiveData が変更されたとき、map に渡した transform が実行されて、変換後の LiveData を取得できます。

例えば、整数値を持つ LiveData の値を 2 倍にしたい場合、以下のような使い方をします。

val before = MutableLiveData(0)
// before を 2 倍にして返す。
val after = before.map { it * 2 }

内部的には MediatorLiveData で実装されており、監視対象が 1 つだけの MediatorLiveData のような振る舞いをします。

switchMap とは?

switchMap も map と同様に LiveData の拡張関数の 1 つです。

public inline fun <X, Y> LiveData<X>.switchMap(
    crossinline transform: (X) -> LiveData<Y>
): LiveData<Y>

使い方も、map と同様に変換したい LiveData に対して変換処理 transform を渡すだけです。

map との違いは、変換処理 transform の中で変換結果を返すとき、値の型ではなくて LiveData 型で返す必要があることです。

よって、さきほどの整数値を 2 倍にする例を switchMap で実装する場合、以下のようになります。

val before = MutableLiveData(0)
// before を 2 倍にして返す。
val after = before.switchMap { MutableLiveData(it * 2) }

switchMap の使い道は、戻り値が LiveData 型のメソッドで変換を行いたいときでしょう。

例えば、Room データベースの DAO で、ID を引数に渡すとその ID に紐付くユーザーデータを読み出すメソッドを変換に使いたい場合です。

@Dao
interface UserDao {

    @Query("SELECT * FROM user WHERE id = :id")
    fun loadUserById(id: Int): LiveData<User>
}
class MainViewModel(
    private val id: Int,
    private val dao: UserDao
) : ViewModel() {

    private val _id = MutableLiveData(id)
    // ID からユーザーデータを読み出す。
    val user = _id.switchMap { dao.loadUserById(it) }

    fun setId(id: Int) {
        _id.value = id
    }
    ︙
}

上記のように switchMap であれば、そのメソッドの戻り値をそのまま返すだけで、LiveData 型のユーザーデータを取得できます。

また、上記の user は LiveData 型なので、user を LiveData#observe にて監視しておけば、ID が変わるたびに user の変更を補足できるようになります。

参考

LiveData を変換する