Android アプリ開発において、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
LiveData とは?
LiveData は、データホルダークラスであり、内部に値を保持します。そして、LiveData は保持する値の変更を監視し、その変更を外部にコールバックで通知します。
よって、LiveData を使用することで、値の変更に追従できるようになります。
また、LiveData は Activity や Fragment などのライフサイクルを考慮して値の変更を通知する機能も持ちます。具体的には、Activity や Fragment がフォアグラウンドに表示されているときだけ通知を行い、バックグラウンドにいるときは通知を行わない、といったことが可能です。これにより、メモリリークやクラッシュを回避できます。
LiveData を使う
実際に LiveData を試してみます。
Button をクリックした回数を ViewModel に保持し、その回数を Activity の TextView に表示してみます。
このとき、Button のクリック回数を素の Int 型で保持するのではなくて、LiveData で保持します。
ライブラリのインポート
LiveData を使えるようにするために、アプリの build.gradle ファイルに次の依存関係を追加します。
dependencies {
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
}
lifecycle-livedata-ktx
をインポートすることにより、LiveData が使えるようになります。また、以降のサンプルでは LiveData を ViewModel に保持するため、lifecycle-viewmodel-ktx
もインポートします。
ViewModel で値を保持する
まず、ViewModel を以下のように実装します。
class MainViewModel : ViewModel() {
/** Button のクリック回数 */
private val _count = MutableLiveData(0)
val count: LiveData<Int> get() = _count
/** クリック回数をカウントアップする。 */
fun countUp() {
_count.value = count.value!! + 1
}
}
最初に、LiveData で値を保持する箇所を見ていきます。
/** Button のクリック回数 */
private val _count = MutableLiveData(0)
val count: LiveData<Int> get() = _count
LiveData には大きく分けて MutableLiveData と LiveData の 2 つのクラスが存在します。この 2 つは以下のような違いがあります。
- MutableLiveData → 値を変更できる
- LiveData → 値を変更できない
LiveData を扱う場合、値の変更は ViewModel 内部に留めて、値の変更通知を受け取る Activity や Fragment などではその値を変更できないようにします。
よって、値そのものは private が付与された MutableLiveData で保持して、それを LiveData に変換したものを ViewModel の外部に公開します。
次に、クリック回数をカウントアップするメソッドを見ていきます。
/** クリック回数をカウントアップする。 */
fun countUp() {
val value = count.value!!
_count.value = value + 1
}
LiveData で保持する値をカウントアップするためには、LiveData からの値の取得と LiveData への値の設定が必要です。これらは以下の 2 つで実現します。
- 値の取得 → LiveData#getValue
- 値の設定 → MutableLiveData#setValue
また、LiveData を扱うときの注意点として、LiveData は値を null 許容型で保持する、というものがあります。よって、LiveData から取得した値を扱う場合、その値を null 安全な型にアンラップする必要があります。
以上により、クリック回数のカウントアップメソッドでは、以下のような流れでクリック回数をカウントアップします。
- count からクリック回数を取得して、null 安全な型にアンラップする。
- クリック回数を +1 加算して、_count に設定する。
Activity で値の変更通知を受け取る
そして、Activity を以下のように実装します。
class MainActivity : AppCompatActivity(R.layout.main_activity) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val viewModel =
ViewModelProvider(this)[MainViewModel::class.java]
// ボタンがクリックされるたびに、クリック回数をカウントアップする。
findViewById<Button>(R.id.button)
.setOnClickListener {
viewModel.countUp()
}
// クリック回数が変更されたら、TextView を更新する。
viewModel.count.observe(this) {
findViewById<TextView>(R.id.text).text = it.toString()
}
}
}
まず、Button がクリックされたら ViewModel のカウントアップメソッドを呼びます。
そして、ViewModel のクリック回数の変更通知を監視します。変更通知を監視するために、以下の LiveData#obseve メソッドを呼びます。
@MainThread
public void observe(@NonNull LifecycleOwner owner,
@NonNull Observer<? super T> observer)
このメソッドに、監視を行う owner と変更通知を受け取ったときに呼び出す observer コールバックを渡します。
owner には、LifecycleOwner インターフェースを継承しているインスタンスを渡します。今回の場合、監視を行うのは Activity であり、MainActivity は LifecycleOwner インターフェースを継承しているので、owner には this を渡します。この owner を渡すことにより、LiveData は owner がアクティブなとき、つまり MainActivity がフォアグラウンドに表示されているときだけ、変更を通知するようになります。
observer コールバックは、変更後のクリック回数を受け取ります。コールバックでは、受け取ったクリック回数を TextView に設定します。(さ)
シンプル入退室管理
限りなくシンプルなタイムカードシステム
monipet
動物病院の犬猫の見守りをサポート
病院を離れる夜間でも安心
moni-stock
一括スキャンで入出庫・棚卸作業にかかる時間を短縮
お客様も現場も笑顔にする在庫管理システム
moni-meter
脱・手書き!点検データをデジタル化して誤検針削減
ローコストで導入しやすい設備点検支援システム
Smart mat
重さセンサIoTで在庫管理に革新を。
自動発注&メールアラートで欠品・発注ミスを防ぎます
株式会社ジェイエスピー
横浜に拠点を置くソフトウェア開発・システム開発・
製品開発(moniシリーズ)、それに農業も手がけるIT企業