Android Kotlin基礎講座 05.2: LiveDataとLiveData observers

タスク:GameViewModelにLiveDataを追加する

LiveDataはライフサイクル対応の監視可能なデータホルダークラスです。例として、GuessTheWordアプリの現在の得点をLiveDataでラッピングできます。この記事では、LiveDataのいくつかの特徴について学習します。

  • LiveDataは監視可能です。これはLiveDataオブジェクトによって保持されているデータに変更があったときにオブザーバーに通知されることを意味しています。
  • LiveDataはデータを保持します。LiveDataはどんなデータにも用いることができるラッパーです。
  • LiveDataはライフサイクル対応です。オブザーバーをLiveDataに取り付けると、オブザーバーはLifecycleOwner(通常はアクティブやフラグメント)と紐づけられます。
    LiveDataはSTARTEDやRESUMEDのようなアクティブなライフサイクル状態の中にあるオブザーバーのみを更新します。LiveDataと監視についてはこちらから詳細が見れます。

このタスクではどのようにして様々なデータ型をLiveDataオブジェクトにラッピングするのかを、GameViewModelの現在の得点と現在の単語をLiveDataに変換することで学習していきます。後のタスクではこれらのLiveDataにオブザーバーを追加し、LiveDataを監視する方法を学習します。

ステップ1:得点と単語をLiveDataを使うようにする

  1. screens/gameパッケージの下のGameViewModelファイルを開いてください。
  2. scoreとword変数の型をMutableLiveDataに変更してください。

    MutableLiveDataとは値が変更可能なLiveDataです。
    MutableLiveDataは汎用クラスなので、それが保持するデータの型を指定する必要があります。
// The current word
val word = MutableLiveData<String>()
// The current score
val score = MutableLiveData<Int>()
  1. GameViewModel中のinitブロックの中で、scoreとwordを初期化してください。LiveData変数の値を変更するためにはその変数に対してsetValue()メソッドを使用します。Kotlinではvalueプロパティを用いてsetValue()を呼び出します。
init {

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

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

score変数とword変数は現在LiveData型になっています。このステップでは、これらの変数の参照をvalueプロパティを用いて変更します。

  1. GameViewModel中のonSkip()メソッドの中のscoreをscore.valueに変更してください。scoreがnullになり得ることに関するエラーが表示されると思います。このエラーは次で解消します。
  2. エラーを解消するために、onSkip()の中でscore.valueに対するnullチェックを追加してください。その後、minus()関数をscoreに対して呼び出します。これはnull安全に減算できる機能です。
fun onSkip() {
   score.value = (score.value)?.minus(1)
   nextWord()
}
  1. 同様にしてonCorrect()メソッドを更新してください。scoreに対してnullチェックを追加し、plus()関数を用いてください。
fun onCorrect() {
   score.value = (score.value)?.plus(1)
   nextWord()
}
  1. GameViewModel中のnextWord()メソッドの中のwordをword.valueに変更してください。
private fun nextWord() {
   if (!wordList.isEmpty()) {
       //Select and remove a word from the list
       word.value = wordList.removeAt(0)
   }
}
  1. GameFragment中のupdateWordText()メソッド中で、viewModel.wordへの参照をviewmodel.word.valueに変更してください。
/** Methods for updating the UI **/
private fun updateWordText() {
   binding.wordText.text = viewModel.word.value
}
  1. GameFragment中のupdateScoreText()メソッド中のviewModel.scoreへの参照をviewModel.score.valueに変更してください。
private fun updateScoreText() {
   binding.scoreText.text = viewModel.score.value.toString()
}
  1. GameViewModel中のgameFinished()メソッド中の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. コードにエラーが発生していないことを確認してください。コンパイルしてアプリを起動してください。アプリの機能は以前と同じはずです。