Android Kotlin の基礎 05.2: LiveData と LiveData のオブザーバー

この Codelab は、Android Kotlin の基礎コースの一部です。Codelab を順番に進めていくと、このコースを最大限に活用できます。すべてのコース Codelab は Android Kotlin の基礎 Codelab ランディング ページに掲載されています。

はじめに

前の Codelab では、GessTheWord アプリで ViewModel を使用して、デバイスの構成変更後もアプリのデータが保持されるようにしました。この Codelab では、LiveDataViewModel クラスのデータと統合する方法を学びます。Android アーキテクチャ コンポーネントの 1 つである LiveData を使用すると、基盤となるデータベースが変更されたときにビューに通知するデータ オブジェクトを作成できます。

LiveData クラスを使用するには、アプリのデータの変化を監視する「オブザーバー」(アクティビティやフラグメントなど)を設定します。LiveData はライフサイクル対応であるため、アクティブなライフサイクルの状態にあるアプリ コンポーネント オブザーバーのみを更新します。

前提となる知識

  • Kotlin で基本的な Android アプリを作成する方法。
  • アプリのデスティネーション間を移動する方法
  • アクティビティとフラグメントのライフサイクル
  • アプリで ViewModel オブジェクトを使用する方法。
  • ViewModelProvider.Factory インターフェースを使用して ViewModel オブジェクトを作成する方法。

学習内容

  • LiveData オブジェクトが役立つ理由。
  • ViewModel に格納されているデータに LiveData を追加する方法。
  • MutableLiveData を使用するタイミングと方法。
  • LiveData. での変更を監視するオブザーバー メソッドを追加する方法
  • バッキング プロパティを使用して LiveData をカプセル化する方法
  • UI コントローラとそれに対応する ViewModel 間の通信方法。

演習内容

  • GuessTheWord アプリで単語とスコアに LiveData を使用する。
  • 単語またはスコアが変化したことに気づくオブザーバーを追加する。
  • 変更された値を表示するテキストビューを更新します。
  • LiveData オブザーバー パターンを使用して、ゲーム終了イベントを追加します。
  • [Play Again] ボタンを実装します。

レッスン 5 の Codelab では、スターター コードから GuessTheWord アプリを開発します。GuessTheWord は 2 人構成のキャラクター スタイル ゲームで、プレーヤーが協力して最高スコアを獲得します。

1 人目のプレーヤーはアプリで単語を確認し、2 人目のプレーヤーに単語を表示しないように順番に実行します。2 人目のプレーヤーがその単語を推測します。

ゲームをプレイするには、最初のプレーヤーがデバイスでアプリを開き、以下のスクリーンショットに示すように「ギター」などの単語が表示されます。

1 人目のプレーヤーが単語を実際に操作し、単語そのものを言わないように注意します。

  • 2 人目のプレーヤーが単語を正しく推測したら、[OK] ボタンを押すと、カウントが 1 つ増えて次の単語が表示されます。
  • 2 人目のプレーヤーが単語を推測できない場合は、[スキップ] ボタンを押すと、カウントが 1 つ減って次の単語に進みます。
  • ゲームを終了するには、[ゲームを終了] ボタンを押します。(この機能は、シリーズの最初の Codelab のスターター コードにはありません)。

この Codelab では、ユーザーがアプリのすべての単語間を移動したときにゲームを終了するイベントを追加して、GuesTheWord アプリを改善します。また、スコアフラグメントに [Play Again] ボタンを追加して、ユーザーがゲームをもう一度プレイできるようにします。

タイトル画面

ゲーム画面

スコア画面

このタスクでは、この Codelab のスターター コードを見つけて実行します。前の Codelab で作成した GuessTheWord アプリをスターター コードとして使用することも、スターター アプリをダウンロードすることもできます。

  1. (省略可)前の Codelab のコードを使用していない場合は、この Codelab のスターター コードをダウンロードします。コードを解凍し、Android Studio でプロジェクトを開きます。
  2. アプリを実行して、ゲームをプレイします。
  3. [Skip] ボタンでは次の単語を表示し、スコアを 1 つ減らします。[Got It] ボタンでは次の単語を表示してスコアを 1 つ増やします。[ゲームを終了] ボタンをクリックするとゲームが終了します。

LiveData はライフサイクル対応の監視可能なデータホルダー クラスです。たとえば、GessTheWord アプリで現在のスコアに LiveData をラップできます。この Codelab では、LiveData のいくつかの特性について説明します。

  • LiveData は監視可能です。つまり、LiveData オブジェクトに保持されているデータが変更されるとオブザーバーに通知されます。
  • LiveData にはデータが保持されます。LiveData はあらゆる種類のデータに使用できるラッパーです。
  • LiveData はライフサイクル対応です。つまり、アクティブなライフサイクル状態(STARTEDRESUMED など)にあるオブザーバーのみを更新します。

このタスクでは、GameViewModel 内の現在のスコアデータと現在の単語データを LiveData に変換して、任意のデータ型を LiveData オブジェクトにラップする方法を学びます。後のタスクで、これらの LiveData オブジェクトにオブザーバーを追加し、LiveData を監視する方法について説明します。

ステップ 1: LiveData を使用するようにスコアと単語を変更する

  1. screens/game パッケージの GameViewModel ファイルを開きます。
  2. 変数 scoreword の型を MutableLiveData に変更します。

    MutableLiveDataLiveData で、値を変更できます。MutableLiveData は汎用のクラスであるため、保持するデータの種類を指定する必要があります。
// The current word
val word = MutableLiveData<String>()
// The current score
val score = MutableLiveData<Int>()
  1. GameViewModelinit ブロック内で、scoreword を初期化します。LiveData 変数の値を変更するには、変数に対して setValue() メソッドを使用します。Kotlin では、value プロパティを使用して setValue() を呼び出すことができます。
init {

   word.value = ""
   score.value = 0
  ...
}

ステップ 2: LiveData オブジェクト参照を更新する

score 変数と word 変数の型が LiveData になりました。このステップでは、value プロパティを使用して、これらの変数への参照を変更します。

  1. GameViewModelonSkip() メソッドで、scorescore.value に変更します。scorenull である可能性があります。このエラーを修正します。
  2. このエラーを解決するには、onSkip()score.valuenull チェックを追加します。次に、scoreminus() 関数を呼び出します。これにより、null の安全性を確保した状態で減算が行われます。
fun onSkip() {
   if (!wordList.isEmpty()) {
       score.value = (score.value)?.minus(1)
   }
   nextWord()
}
  1. 同じ方法で onCorrect() メソッドを更新します。score 変数に null チェックを追加し、plus() 関数を使用します。
fun onCorrect() {
   if (!wordList.isEmpty()) {
       score.value = (score.value)?.plus(1)
   }
   nextWord()
}
  1. GameViewModelnextWord() メソッド内で、word 参照を word.value に変更します。
private fun nextWord() {
   if (!wordList.isEmpty()) {
       //Select and remove a word from the list
       word.value = wordList.removeAt(0)
   }
}
  1. GameFragmentupdateWordText() メソッド内で、viewModel.word への参照を viewModel.word.value. に変更します。
/** Methods for updating the UI **/
private fun updateWordText() {
   binding.wordText.text = viewModel.word.value
}
  1. GameFragmentupdateScoreText() メソッド内で、viewModel.score への参照を viewModel.score.value. に変更します。
private fun updateScoreText() {
   binding.scoreText.text = viewModel.score.value.toString()
}
  1. GameFragmentgameFinished() メソッド内で、参照を viewModel.score から viewModel.score.value に変更します。必要な null 安全確認を追加します。
private fun gameFinished() {
   Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
   val action = GameFragmentDirections.actionGameToScore()
   action.score = viewModel.score.value?:0
   NavHostFragment.findNavController(this).navigate(action)
}
  1. コードにエラーがないことを確認します。アプリをコンパイルして実行します。アプリの機能は以前と同じになります。

このタスクは、スコアと単語のデータを LiveData オブジェクトに変換した前のタスクと密接に関連しています。このタスクでは、これらの LiveData オブジェクトに Observer オブジェクトをアタッチします。

  1. GameFragment,onCreateView() メソッドで、現在のスコア viewModel.scoreLiveData オブジェクトに Observer オブジェクトをアタッチします。observe() メソッドを使用し、viewModel の初期化後にコードを配置します。ラムダ式を使用してコードを簡略化します。(ラムダ式は、宣言されていないが、すぐに式として渡される匿名関数です)。
viewModel.score.observe(this, Observer { newScore ->
})

Observer への参照を解決します。これを行うには、Observer をクリックし、Alt+Enter(Mac では Option+Enter)を押して、androidx.lifecycle.Observer をインポートします。

  1. 作成したオブザーバーは、監視対象の LiveData オブジェクトによって保持されているデータが変更されたときにイベントを受信します。オブザーバー内で、スコア TextView を新しいスコアに更新します。
/** Setting up LiveData observation relationship **/
viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})
  1. 現在の単語 LiveData オブジェクトに Observer オブジェクトをアタッチします。このメソッドは、Observer オブジェクトを現在のスコアにアタッチするのと同じ方法で実行します。
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
   binding.wordText.text = newWord
})

score または word の値が変更されると、画面に表示される score または word が自動的に更新されます。

  1. GameFragment で、メソッド updateWordText() および updateScoreText()、およびこれらへのすべての参照を削除します。LiveData オブザーバー メソッドによってテキストビューが更新されるため、今後は不要です。
  2. アプリを実行します。ゲームアプリはこれまでとまったく同じように機能するはずですが、現在は LiveData オブザーバーと LiveData オブザーバーを使用しています。

カプセル化は、オブジェクトの一部のフィールドへの直接アクセスを制限する方法です。オブジェクトをカプセル化する場合は、非公開の内部フィールドを変更するためのパブリック メソッドを公開します。カプセル化することで、内部フィールドに対する他のクラスからの操作を制御できます。

現在のコードでは、外部クラスが value プロパティを使用して viewModel.score.value などの score 変数と word 変数を変更できます。この Codelab で開発を行うアプリで問題ないかもしれませんが、本番環境アプリでは ViewModel オブジェクトのデータを管理する必要があります。

アプリ内のデータを編集できるのは ViewModel のみです。ただし、UI コントローラはデータを読み取る必要があるため、データ フィールドを完全に非公開にすることはできません。アプリのデータをカプセル化するには、MutableLiveData オブジェクトと LiveData オブジェクトの両方を使用します。

MutableLiveDataLiveData:

  • MutableLiveData オブジェクトのデータは、その名前のとおり変更できます。ViewModel 内ではデータを編集できるように、MutableLiveData を使用します。
  • LiveData オブジェクトのデータは読み取ることはできますが、変更することはできません。ViewModel の外部からは、データを読み取り可能にし、変更は不可能にする必要があるため、データを LiveData として公開する必要があります。

この方法を実現するには、Kotlin バッキング プロパティを使用します。バッキング プロパティを使用すると、そのオブジェクト自体ではなくゲッターから返すことができます。このタスクでは、GuesTheWord アプリに score オブジェクトと word オブジェクトのバッキング プロパティを実装します。

スコアと単語にバッキング プロパティを追加する

  1. GameViewModel で、現在の score オブジェクトを private に設定します。
  2. バッキング プロパティで使用される命名規則に従って、score_score に変更します。_score プロパティが、内部で使用されるゲームスコアの可変バージョンになりました。
  3. score という LiveData 型の公開バージョンを作成します。
// The current score
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
  1. 初期化エラーが表示されます。このエラーは、GameFragment 内で scoreLiveData 参照であり、score がそのセッターにアクセスできないためです。Kotlin のゲッターとセッターの詳細については、ゲッターとセッターをご覧ください。

    エラーを解決するには、GameViewModel にある score オブジェクトの get() メソッドをオーバーライドし、バッキング プロパティ _score を返します。
val score: LiveData<Int>
   get() = _score
  1. GameViewModel で、score の参照を内部で変更可能なバージョン _score に変更します。
init {
   ...
   _score.value = 0
   ...
}

...
fun onSkip() {
   if (!wordList.isEmpty()) {
       _score.value = (score.value)?.minus(1)
   }
  ...
}

fun onCorrect() {
   if (!wordList.isEmpty()) {
       _score.value = (score.value)?.plus(1)
   }
   ...
}
  1. score オブジェクトの場合と同様に、word オブジェクトの名前を _word に変更し、そのバッキング プロパティを追加します。
// The current word
private val _word = MutableLiveData<String>()
val word: LiveData<String>
   get() = _word
...
init {
   _word.value = ""
   ...
}
...
private fun nextWord() {
   if (!wordList.isEmpty()) {
       //Select and remove a word from the list
       _word.value = wordList.removeAt(0)
   }
}

これで、LiveData オブジェクトの wordscore がカプセル化されました。

ユーザーが [ゲームを終了] ボタンをタップすると、現在のアプリがスコア画面に移動します。また、プレーヤーがすべての単語を切り替えたときに、スコア画面に移動するようにします。プレーヤーが最後の単語でゲームを終えたら、ユーザーがボタンをタップしなくてもゲームを自動的に終了できるようにします。

この機能を実装するには、すべての単語が表示されたときにイベントをトリガーし、ViewModel からフラグメントに伝える必要があります。これを行うには、LiveData オブザーバー パターンを使用して、ゲーム終了イベントをモデル化します。

オブザーバー パターン

オブザーバー パターンは、ソフトウェア設計パターンです。オブジェクト間の通信を指定する。監視可能(観測の「対象」)とオブザーバーです。オブザーバブルは、オブザーバーの状態の変化をオブザーバーに通知するオブジェクトです。

このアプリの LiveData の場合、オブザーバブル(サブジェクト)は LiveData オブジェクトで、オブザーバーはフラグメントなどの UI コントローラのメソッドです。状態の変化は、LiveData 内にラップされたデータが変更されるたびに発生します。LiveData クラスは、ViewModel からフラグメントへの通信において非常に重要です。

ステップ 1: LiveData を使用して、ゲーム終了イベントを検出する

このタスクでは、LiveData オブザーバー パターンを使用して、ゲーム終了イベントをモデル化します。

  1. GameViewModel で、_eventGameFinish という Boolean MutableLiveData オブジェクトを作成します。このオブジェクトは、ゲーム終了イベントを保持します。
  2. _eventGameFinish オブジェクトを初期化したら、eventGameFinish というバッキング プロパティを作成して初期化します。
// Event which triggers the end of the game
private val _eventGameFinish = MutableLiveData<Boolean>()
val eventGameFinish: LiveData<Boolean>
   get() = _eventGameFinish
  1. GameViewModelonGameFinish() メソッドを追加します。このメソッドで、ゲーム終了イベント eventGameFinishtrue に設定します。
/** Method for the game completed event **/
fun onGameFinish() {
   _eventGameFinish.value = true
}
  1. GameViewModelnextWord() メソッド内で、単語リストが空の場合はゲームを終了します。
private fun nextWord() {
   if (wordList.isEmpty()) {
       onGameFinish()
   } else {
       //Select and remove a _word from the list
       _word.value = wordList.removeAt(0)
   }
}
  1. GameFragment で、onCreateView() 内の viewModel を初期化した後、オブザーバーを eventGameFinish にアタッチします。observe() メソッドを使用します。ラムダ関数内で、gameFinished() メソッドを呼び出します。
// Observer for the Game finished event
viewModel.eventGameFinish.observe(this, Observer<Boolean> { hasFinished ->
   if (hasFinished) gameFinished()
})
  1. アプリを実行して、ゲームをプレイし、すべての単語を確認してください。[ゲームを終了] をタップするまで、ゲームのフラグメントに留まるのではなく、自動的にスコア画面に移動する。

    単語リストが空の場合、eventGameFinish が設定され、ゲーム フラグメントの関連するオブザーバー メソッドが呼び出され、アプリは画面フラグメントに移動します。
  2. 追加したコードにより、ライフサイクルの問題が発生しています。この問題について理解するには、GameFragment クラスで、gameFinished() メソッドのナビゲーション コードをコメントアウトします。必ず、Toast メッセージをメソッドに保持してください。
private fun gameFinished() {
       Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
//        val action = GameFragmentDirections.actionGameToScore()
//        action.score = viewModel.score.value?:0
//        NavHostFragment.findNavController(this).navigate(action)
   }
  1. アプリを実行して、ゲームをプレイし、すべての単語を確認してください。「ゲームが終了しました」というトースト メッセージがゲーム画面の下部に一時的に表示されます。これは想定された動作です。

デバイスまたはエミュレータを回転します。トーストが再び表示されます。デバイスをさらに回転させると、トーストが毎回表示されるはずです。トーストはゲーム終了時に 1 回だけ表示されるため、これはバグです。フラグメントが再作成されるたびに、トーストが表示されるべきではありません。この問題は、次のタスクで解決します。

ステップ 2: ゲーム終了イベントをリセットする

通常、LiveData はデータが変更された場合にのみオブザーバーを更新します。オブザーバーは非アクティブな状態からアクティブな状態に変わったときにもオブザーバーを受け取ります。ただし、この動作は例外です。

そのため、ゲーム終了のトーストはアプリで繰り返しトリガーされます。ゲーム フラグメントが画面の回転後に再作成されると、非アクティブ状態からアクティブ状態に遷移します。フラグメント内のオブザーバーが既存の ViewModel に再接続され、現在のデータを受け取ります。gameFinished() メソッドが再度トリガーされ、トーストが表示されます。

このタスクでは、この問題を修正し、GameViewModeleventGameFinish フラグをリセットして、トーストを 1 回だけ表示します。

  1. GameViewModel に、ゲーム終了イベント _eventGameFinish をリセットする onGameFinishComplete() メソッドを追加します。
/** Method for the game completed event **/

fun onGameFinishComplete() {
   _eventGameFinish.value = false
}
  1. GameFragmentgameFinished() の最後で、viewModel オブジェクトの onGameFinishComplete() を呼び出します。(現時点では、gameFinished() のナビゲーション コードはコメントアウトしたままにします)。
private fun gameFinished() {
   ...
   viewModel.onGameFinishComplete()
}
  1. アプリを実行して、ゲームをプレイします。すべての単語を確認し、デバイスの画面の向きを変更します。トーストは 1 回だけ表示されます。
  2. GameFragmentgameFinished() メソッド内で、ナビゲーション コードのコメントを解除します。

    Android Studio でコメント化を解除するには、コメントアウトした行を選択して、Control+/(Mac では Command+/)を押します。
private fun gameFinished() {
   Toast.makeText(activity, "Game has just finished", Toast.LENGTH_SHORT).show()
   val action = GameFragmentDirections.actionGameToScore()
   action.score = viewModel.score.value?:0
   findNavController(this).navigate(action)
   viewModel.onGameFinishComplete()
}

Android Studio のプロンプトが表示されたら、androidx.navigation.fragment.NavHostFragment.findNavController をインポートします。

  1. アプリを実行して、ゲームをプレイします。すべての単語を確認したら、自動的に最終スコアの画面に移動します。

お疲れさまでした。アプリは LiveData を使用して、ゲーム終了のイベントをトリガーし、GameViewModel から単語リストが空であることをゲーム フラグメントに知らせます。次に、ゲーム フラグメントがスコア フラグメントに移動します。

このタスクでは、スコアを ScoreViewModelLiveData オブジェクトに変更し、オブザーバーをアタッチします。このタスクは、LiveDataGameViewModel に追加したときのタスクと似ています。

完全性のためにこれらの変更を ScoreViewModel に変更し、アプリのすべてのデータで LiveData を使用できるようにします。

  1. ScoreViewModel で、score 変数タイプを MutableLiveData に変更します。慣例として、名前を _score に変更し、バッキング プロパティを追加します。
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
   get() = _score
  1. ScoreViewModelinit ブロック内で、_score を初期化します。ログは init ブロックで必要に応じて削除できます。
init {
   _score.value = finalScore
}
  1. ScoreFragmentonCreateView() 内で、viewModel を初期化した後、スコア LiveData オブジェクトのオブザーバーをアタッチします。ラムダ式内で、スコア値をスコア テキストビューに設定します。ViewModel からスコア値を含むテキストビューを直接割り当てるコードを削除します。

追加するコード:

// Add observer for score
viewModel.score.observe(this, Observer { newScore ->
   binding.scoreText.text = newScore.toString()
})

削除するコード:

binding.scoreText.text = viewModel.score.toString()

Android Studio のプロンプトが表示されたら、androidx.lifecycle.Observer をインポートします。

  1. アプリを実行してゲームをプレイします。アプリは通常どおり動作しますが、LiveData とオブザーバーを使用してスコアを更新します。

このタスクでは、スコア画面に [Play Again] ボタンを追加し、LiveData イベントを使用してクリック リスナーを実装します。このボタンは、スコア画面からゲーム画面に移動するイベントをトリガーします。

アプリのスターター コードには [Play Again] ボタンがありますが、ボタンは非表示になっています。

  1. res/layout/score_fragment.xml の [play_again_button] ボタンで、visibility 属性の値を visible に変更します。
<Button
   android:id="@+id/play_again_button"
...
   android:visibility="visible"
 />
  1. ScoreViewModel に、_eventPlayAgain という Boolean を保持する LiveData オブジェクトを追加します。このオブジェクトは、LiveData イベントを保存し、スコア画面からゲーム画面に移動するために使用されます。
private val _eventPlayAgain = MutableLiveData<Boolean>()
val eventPlayAgain: LiveData<Boolean>
   get() = _eventPlayAgain
  1. ScoreViewModel で、イベント _eventPlayAgain を設定およびリセットするメソッドを定義します。
fun onPlayAgain() {
   _eventPlayAgain.value = true
}
fun onPlayAgainComplete() {
   _eventPlayAgain.value = false
}
  1. ScoreFragment に、eventPlayAgain のオブザーバーを追加します。コードは、onCreateView() の最後、return ステートメントの前に配置します。ラムダ式内で、ゲーム画面に戻り、eventPlayAgain をリセットします。
// Navigates back to game when button is pressed
viewModel.eventPlayAgain.observe(this, Observer { playAgain ->
   if (playAgain) {
      findNavController().navigate(ScoreFragmentDirections.actionRestart())
       viewModel.onPlayAgainComplete()
   }
})

Android Studio のプロンプトが表示されたら、androidx.navigation.fragment.findNavController をインポートします。

  1. ScoreFragment で、onCreateView() 内の [PlayAgain] ボタンにクリック リスナーを追加し、viewModel.onPlayAgain() を呼び出します。
binding.playAgainButton.setOnClickListener {  viewModel.onPlayAgain()  }
  1. アプリを実行してゲームをプレイします。ゲームが終了すると、スコア画面に最終スコアと [Play Again] ボタンが表示されます。[PlayAgain] ボタンをタップして、ゲーム画面に移動し、もう一度ゲームをプレイできるようにします。

よかったですね!ViewModelLiveData オブジェクトを使用するようにアプリのアーキテクチャを変更し、オブザーバーを LiveData オブジェクトに接続しました。LiveData は、LiveData が保持する値が変更されたときにオブザーバー オブジェクトに通知します。

Android Studio プロジェクト: GuessTheWord

LiveData

  • LiveData はライフサイクル対応の監視可能なデータホルダー クラスで、Android アーキテクチャ コンポーネントの 1 つです。
  • LiveData を使用すると、データ更新時に UI を自動更新できます。
  • LiveData は監視可能です。つまり、LiveData オブジェクトによって保持されているデータが変更されたときに、アクティビティやフラグメントなどのオブザーバーに通知できます。
  • LiveData はデータを保持します。これは任意のデータに使用できるラッパーです。
  • LiveData はライフサイクル対応です。つまり、アクティブなライフサイクル状態(STARTEDRESUMED など)にあるオブザーバーのみを更新します。

LiveData を追加する

  • ViewModel 内のデータ変数の型を LiveData または MutableLiveData に変更します。

MutableLiveData は、値を変更できる LiveData オブジェクトです。MutableLiveData は汎用のクラスであるため、保持するデータの種類を指定する必要があります。

  • LiveData が保持するデータの値を変更するには、LiveData 変数に対して setValue() メソッドを使用します。

LiveData をカプセル化する

  • ViewModel 内の LiveData は編集できる必要があります。ViewModel の外部で、LiveData が読み取り可能になっている必要があります。これは、Kotlin バッキング プロパティを使用して実装できます。
  • Kotlin バッキング プロパティを使用すると、そのオブジェクト自体ではなくゲッターから返すことができます。
  • LiveData をカプセル化するには、ViewModel 内で private MutableLiveData を使用し、ViewModel の外部で LiveData バッキング プロパティを返します。

オブザーバブル LiveData

  • LiveData はオブザーバー パターンに従います。「オブザーバブル」は LiveData オブジェクトで、オブザーバーはフラグメントなどの UI コントローラのメソッドです。LiveData 内にラップされたデータが変更されるたびに、UI コントローラのオブザーバー メソッドに通知されます。
  • LiveData をオブザーバブルにするには、observe() メソッドを使用してオブザーバー(アクティビティやフラグメントなど)の LiveData 参照にオブザーバー オブジェクトを追加します。
  • この LiveData オブザーバー パターンを使用すると、ViewModel から UI コントローラと通信できます。

Udacity コース:

Android デベロッパー ドキュメント:

その他:

このセクションでは、インストラクターが主導するコースの一環として、この Codelab に取り組む生徒の課題について説明します。教師は以下のことを行えます。

  • 必要に応じて課題を割り当てます。
  • 宿題の提出方法を生徒に伝える。
  • 宿題を採点します。

教師はこれらの提案を少しだけ使うことができます。また、他の課題は自由に割り当ててください。

この Codelab にご自分で取り組む場合は、これらの課題を使用して知識をテストしてください。

次の質問に答えてください。

問題 1

ViewModel に保存されている LiveData をカプセル化して、外部オブジェクトがデータを更新せずに読み取るにはどうすればよいでしょうか。

  • ViewModel オブジェクト内で、データのデータ型を private LiveData に変更します。バッキング プロパティを使用して、MutableLiveData 型の読み取り専用データを公開する。
  • ViewModel オブジェクト内で、データのデータ型を private MutableLiveData に変更します。バッキング プロパティを使用して、LiveData 型の読み取り専用データを公開する。
  • UI コントローラ内で、データのデータ型を private MutableLiveData に変更します。バッキング プロパティを使用して、LiveData 型の読み取り専用データを公開する。
  • ViewModel オブジェクト内で、データのデータ型を LiveData に変更します。バッキング プロパティを使用して、LiveData 型の読み取り専用データを公開する。

質問 2

LiveData が UI コントローラ(フラグメントなど)を更新する場合、UI コントローラが次のどの状態にあるか。

  • 再開
  • バックグラウンド
  • 一時停止
  • 停止

問題 3

LiveData オブザーバー パターンで、監視可能なアイテム(監視対象のアイテム)は何ですか?

  • オブザーバー メソッド
  • LiveData オブジェクト内のデータ
  • UI コントローラ
  • ViewModel オブジェクト

次のレッスンを開始する: 5.3: ViewModel と LiveData を使ったデータ バインディング

このコースの他の Codelab へのリンクについては、Android Kotlin の基礎 Codelab ランディング ページをご覧ください。