今回は、MediatorLiveData で他の 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
MediatorLiveData は LiveData のサブクラスであり、他の LiveData の値を監視して自身の値を変更することができます。
以下が、監視対象を追加するメソッドです。
引数 source に監視対象の LiveData を設定します。そして、引数 onChanged に引数 source が変更されたときに呼び出されるコールバックを設定します。
なお、1 つの MediatorLiveData で、2 つ以上の LiveData を監視することが可能です。
しかし、MediatorLiveData は 1 つの LiveData に対して 2 つ以上のコールバックを設定することができません。
以下のように、すでに監視を開始している LiveData に対して、異なるコールバックを設定した場合、MediatorLiveData#addSource は IllegalArgumentException を投げます。
監視を停止したい場合には、以下の MediatorLiveData#removeSource を使います。
実際に MediatorLiveData を試してみます。
今回は、Activity と ViewModel、そして、String 型の値を持つ LiveData を 2 つとそれらを結合する MediatorLiveData を 1 つ用意します。MediatorLiveData は、2 つの LiveData を監視し、それらが変更されるたびに 2 つの LiveData を結合して自身に格納します。
上記の 3 つの LiveData を ViewModel に保持し、Activity から結合元となる 2 つの LiveData の変更と MediatorLiveData の監視を行います。
MediatorLiveData を使えるようにするために、アプリの build.gradle ファイルに次の依存関係を追加します。
まず、ViewModel を以下のように実装します。
監視の開始を init で行います。2 つの LiveData ごとに addSource を呼び出します。監視対象が変更されたら、もう一方の LiveData と結合して、自身に格納します。
そして、Activity を以下のように実装します。
Activity のレイアウトには、2 つの LiveData ごとに EditText を用意し、それらのテキストの変更を監視し、テキストを ViewModel の LiveData に格納します。
そして、2 つの LiveData を結合した `linkedStr` を監視し、その値を TextView に表示します。
こうすることにより、2 つの EditText に入力したテキストを結合したものが TextView に表示されるようになります。(さ)
シンプル入退室管理
限りなくシンプルなタイムカードシステム
monipet
動物病院の犬猫の見守りをサポート
病院を離れる夜間でも安心
moni-stock
一括スキャンで入出庫・棚卸作業にかかる時間を短縮
お客様も現場も笑顔にする在庫管理システム
moni-meter
脱・手書き!点検データをデジタル化して誤検針削減
ローコストで導入しやすい設備点検支援システム
Smart mat
重さセンサIoTで在庫管理に革新を。
自動発注&メールアラートで欠品・発注ミスを防ぎます
株式会社ジェイエスピー
横浜に拠点を置くソフトウェア開発・システム開発・
製品開発(moniシリーズ)、それに農業も手がけるIT企業
なお、ここに掲載しているソースコードは以下の環境で動作確認しています。
- 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
MediatorLiveData とは?
MediatorLiveData は LiveData のサブクラスであり、他の LiveData の値を監視して自身の値を変更することができます。
以下が、監視対象を追加するメソッドです。
@MainThread
public <S> void addSource(@NonNull LiveData<S> source,
@NonNull Observer<? super S> onChanged)
引数 source に監視対象の LiveData を設定します。そして、引数 onChanged に引数 source が変更されたときに呼び出されるコールバックを設定します。
なお、1 つの MediatorLiveData で、2 つ以上の LiveData を監視することが可能です。
// OK
mediator.apply {
addSource(source1) { mediator = it }
addSource(source2) { mediator = it }
}
しかし、MediatorLiveData は 1 つの LiveData に対して 2 つ以上のコールバックを設定することができません。
以下のように、すでに監視を開始している LiveData に対して、異なるコールバックを設定した場合、MediatorLiveData#addSource は IllegalArgumentException を投げます。
// NG
mediator.apply {
addSource(source1) { mediator = it }
addSource(source1) { mediator = "source1: $it" }
}
監視を停止したい場合には、以下の MediatorLiveData#removeSource を使います。
@MainThread
public void <S> removeSource(@NonNull LiveData<S> toRemote)
MediatorLiveData を使う
実際に MediatorLiveData を試してみます。
今回は、Activity と ViewModel、そして、String 型の値を持つ LiveData を 2 つとそれらを結合する MediatorLiveData を 1 つ用意します。MediatorLiveData は、2 つの LiveData を監視し、それらが変更されるたびに 2 つの LiveData を結合して自身に格納します。
上記の 3 つの LiveData を ViewModel に保持し、Activity から結合元となる 2 つの LiveData の変更と MediatorLiveData の監視を行います。
ライブラリのインポート
MediatorLiveData を使えるようにするために、アプリの build.gradle ファイルに次の依存関係を追加します。
dependencies {
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
}
lifecycle-livedata-ktx
をインポートすることにより、MediatorLiveData が使えるようになります。また、以降のサンプルでは LiveData を ViewModel に保持するため、lifecycle-viewmodel-ktx
もインポートします。ViewModel で値の保持と結合を行う
まず、ViewModel を以下のように実装します。
class MainViewModel : ViewModel() {
// editText1 の文字列
val str1 = MutableLiveData("")
// editText2 の文字列
val str2 = MutableLiveData("")
// editText1 と editText2 の結合
val linkedStr: MediatorLiveData<String> = MediatorLiveData()
init {
linkedStr.apply {
// str1 の変更を監視する。
addSource(str1) {
linkedStr.value = "$it ${str2.value!!}"
}
// str2 の変更を監視する。
addSource(str2) {
linkedStr.value = "${str1.value!!} $it"
}
}
}
}
監視の開始を init で行います。2 つの LiveData ごとに addSource を呼び出します。監視対象が変更されたら、もう一方の LiveData と結合して、自身に格納します。
Activity で LiveData の変更と MediatorLiveData の監視を行う
そして、Activity を以下のように実装します。
class MainActivity : AppCompatActivity(R.layout.main_activity) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val viewModel =
ViewModelProvider(this)[MainViewModel::class.java]
// editText1 の文字列変更を str1 に反映する。
findViewById<EditText>(R.id.editText1)
.doOnTextChanged { text, _, _, _ ->
viewModel.str1.value = (text ?: "").toString()
}
// editText2 の文字列変更を str2 に反映する。
findViewById<EditText>(R.id.editText2)
.doOnTextChanged { text, _, _, _ ->
viewModel.str2.value = (text ?: "").toString()
}
viewModel.linkedStr.observe(this) {
findViewById<TextView>(R.id.text).text = it
}
}
}
Activity のレイアウトには、2 つの LiveData ごとに EditText を用意し、それらのテキストの変更を監視し、テキストを ViewModel の LiveData に格納します。
そして、2 つの LiveData を結合した `linkedStr` を監視し、その値を TextView に表示します。
こうすることにより、2 つの EditText に入力したテキストを結合したものが TextView に表示されるようになります。(さ)
シンプル入退室管理
限りなくシンプルなタイムカードシステム
monipet
動物病院の犬猫の見守りをサポート
病院を離れる夜間でも安心
moni-stock
一括スキャンで入出庫・棚卸作業にかかる時間を短縮
お客様も現場も笑顔にする在庫管理システム
moni-meter
脱・手書き!点検データをデジタル化して誤検針削減
ローコストで導入しやすい設備点検支援システム
Smart mat
重さセンサIoTで在庫管理に革新を。
自動発注&メールアラートで欠品・発注ミスを防ぎます
株式会社ジェイエスピー
横浜に拠点を置くソフトウェア開発・システム開発・
製品開発(moniシリーズ)、それに農業も手がけるIT企業