この Codelab は、Android Kotlin の基礎コースの一部です。このコースを最大限に活用するには、Codelab を順番に進めることをおすすめします。コースのすべての Codelab は、Android Kotlin の基礎の Codelab のランディング ページに一覧表示されています。
はじめに
前の Codelab では、GuessTheWord アプリで ViewModel
を使用して、デバイスの構成変更後もアプリのデータを維持できるようにしました。この Codelab では、LiveData
を ViewModel
クラスのデータと統合する方法を学びます。LiveData
は Android アーキテクチャ コンポーネントの 1 つで、基盤となるデータベースが変更されたときにビューに通知するデータ オブジェクトを構築できます。
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 人のプレーヤーが最高スコアを目指して協力する、2 プレーヤー ジェスチャー ゲームです。
最初のプレーヤーはアプリの単語を見て、2 番目のプレーヤーに単語を見せないようにしながら、各単語を順番に演じます。2 人目のプレーヤーが単語を当てようとします。
ゲームをプレイするには、最初のプレーヤーがデバイスでアプリを開き、下のスクリーンショットに示すように、「ギター」などの単語を表示します。
最初のプレーヤーは、単語自体を言わないように注意しながら、単語を演じます。
- 2 人目のプレーヤーが単語を正しく当てると、1 人目のプレーヤーが [Got It] ボタンを押します。これにより、カウントが 1 つ増え、次の単語が表示されます。
- 2 人目のプレーヤーが単語を当てられない場合、1 人目のプレーヤーが [スキップ] ボタンを押します。これにより、カウントが 1 減り、次の単語にスキップします。
- ゲームを終了するには、[End Game] ボタンを押します。(この機能は、シリーズの最初の Codelab のスターター コードには含まれていません)。
この Codelab では、ユーザーがアプリ内のすべての単語を使い切ったときにゲームを終了するイベントを追加して、GuessTheWord アプリを改善します。また、スコア フラグメントに [もう一度プレイ ] ボタンを追加して、ユーザーがゲームをもう一度プレイできるようにします。
タイトル画面 | ゲーム画面 | スコア画面 |
このタスクでは、この Codelab のスターター コードを見つけて実行します。前の Codelab で作成した GuessTheWord アプリをスターター コードとして使用することも、スターター アプリをダウンロードすることもできます。
- (省略可)前の Codelab のコードを使用しない場合は、この Codelab のスターター コードをダウンロードします。コードの ZIP ファイルを展開し、プロジェクトを Android Studio で開きます。
- アプリを実行して、ゲームをプレイします。
- [Skip] ボタンをタップすると、次の単語が表示され、スコアが 1 減ります。[Got It] ボタンをタップすると、次の単語が表示され、スコアが 1 増えます。[ゲームを終了] ボタンをクリックすると、ゲームが終了します。
LiveData
は、ライフサイクル対応の監視可能なデータホルダー クラスです。たとえば、GuessTheWord アプリの現在のスコアを LiveData
でラップできます。この Codelab では、LiveData
のいくつかの特性について学びます。
LiveData
は監視可能です。つまり、LiveData
オブジェクトに保持されているデータが変更されるとオブザーバーに通知されます。LiveData
にはデータが保持されます。LiveData
はあらゆる種類のデータに使用できるラッパーです。LiveData
はライフサイクル対応です。つまり、STARTED
やRESUMED
などのアクティブなライフサイクルの状態にあるオブザーバーのみを更新します。
このタスクでは、GameViewModel
にある現在のスコアと現在の単語のデータを LiveData
に変換することによって、あらゆるデータ型を LiveData
オブジェクトにラップする方法を学びます。後のタスクでは、これらの LiveData
オブジェクトにオブザーバーを追加し、LiveData
を監視する方法を学びます。
ステップ 1: LiveData を使用するようにスコアと単語を変更する
screens/game
パッケージで、GameViewModel
ファイルを開きます。- 変数
score
と変数word
の型をMutableLiveData
に変更します。MutableLiveData
は、値を変更できるLiveData
です。MutableLiveData
は汎用のクラスであるため、保持するデータの種類を指定する必要があります。
// The current word
val word = MutableLiveData<String>()
// The current score
val score = MutableLiveData<Int>()
GameViewModel
のinit
ブロック内で、score
とword
を初期化します。LiveData
変数の値を変更するには、変数に対してsetValue()
メソッドを使用します。Kotlin では、value
プロパティを使用してsetValue()
を呼び出すことができます。
init {
word.value = ""
score.value = 0
...
}
ステップ 2: LiveData オブジェクト参照を更新する
score
変数と word
変数が LiveData
型になりました。このステップでは、value
プロパティを使用して、これらの変数への参照を変更します。
GameViewModel
のonSkip()
メソッドで、score
をscore.value
に変更します。score
がnull
である可能性があるというエラーが表示されます。このエラーを修正します。- このエラーを解決するには、
onSkip()
のscore.value
にnull
チェックを追加します。次に、score
でminus()
関数を呼び出します。この関数はnull
-safety で減算を行います。
fun onSkip() {
if (!wordList.isEmpty()) {
score.value = (score.value)?.minus(1)
}
nextWord()
}
- 同様に
onCorrect()
メソッドを更新します。score
変数にnull
チェックを追加し、plus()
関数を使用します。
fun onCorrect() {
if (!wordList.isEmpty()) {
score.value = (score.value)?.plus(1)
}
nextWord()
}
GameViewModel
のnextWord()
メソッド内で、word
の参照をword
.
value
に変更します。
private fun nextWord() {
if (!wordList.isEmpty()) {
//Select and remove a word from the list
word.value = wordList.removeAt(0)
}
}
GameFragment
のupdateWordText()
メソッド内で、viewModel
.word
への参照をviewModel
.
word
.
value.
に変更します。
/** Methods for updating the UI **/
private fun updateWordText() {
binding.wordText.text = viewModel.word.value
}
GameFragment
のupdateScoreText()
メソッド内で、viewModel
.score
への参照をviewModel
.
score
.
value.
に変更します。
private fun updateScoreText() {
binding.scoreText.text = viewModel.score.value.toString()
}
GameFragment
の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)
}
- コードにエラーがないことを確認します。アプリをコンパイルして実行します。アプリの機能は以前と同じであるはずです。
このタスクは、スコアと単語のデータを LiveData
オブジェクトに変換した前のタスクと密接に関連しています。このタスクでは、Observer
オブジェクトをこれらの LiveData
オブジェクトに接続します。
onCreateView()
メソッド内のGameFragment,
で、現在のスコアviewModel.score
のLiveData
オブジェクトにObserver
オブジェクトをアタッチします。observe()
メソッドを使用し、viewModel
の初期化後にコードを配置します。ラムダ式を使用してコードを簡素化します。(ラムダ式は、宣言されない匿名関数であり、式としてその場で渡されます)。
viewModel.score.observe(this, Observer { newScore ->
})
Observer
への参照を解決します。これを行うには、Observer
をクリックして Alt+Enter
(Mac の場合は Option+Enter
)を押し、androidx.lifecycle.Observer
をインポートします。
- 作成したオブザーバーは、監視対象の
LiveData
オブジェクトに保持されているデータが変更されるとイベントを受け取ります。オブザーバー内で、スコアTextView
を新しいスコアで更新します。
/** Setting up LiveData observation relationship **/
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})
Observer
オブジェクトを現在の単語のLiveData
オブジェクトにアタッチします。Observer
オブジェクトを現在のスコアに関連付けたときと同じ方法で行います。
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
binding.wordText.text = newWord
})
score
または word
の値が変更されると、画面に表示される score
または word
が自動的に更新されます。
GameFragment
で、メソッドupdateWordText()
とupdateScoreText()
、およびそれらへの参照をすべて削除します。テキスト ビューはLiveData
オブザーバー メソッドによって更新されるため、これらは不要になりました。- アプリを実行します。ゲームアプリは、前とまったく同じように動作しますが、
LiveData
とLiveData
オブザーバーを使用するようになります。
カプセル化により、オブジェクトの一部フィールドへの直接アクセスを制限できます。オブジェクトをカプセル化する場合は、非公開の内部フィールドを変更するためのパブリック メソッドを公開します。カプセル化することで、内部フィールドに対する他のクラスからの操作を制御できます。
現在のコードでは、外部クラスは value
プロパティ(たとえば viewModel.score.value
)を使用して score
変数と word
変数を変更できます。この Codelab で開発するアプリでは問題にならないかもしれませんが、本番環境のアプリでは、ViewModel
オブジェクト内のデータを制御する必要があります。
アプリ内のデータを編集できるのは ViewModel
のみです。ただし、UI コントローラはデータを読み取る必要があるため、データ フィールドを完全に非公開にすることはできません。アプリのデータをカプセル化するには、MutableLiveData
オブジェクトと LiveData
オブジェクトの両方を使用します。
MutableLiveData
対 LiveData
:
MutableLiveData
オブジェクト内のデータは、名前が示すように変更できます。ViewModel
内ではデータを編集できるように、MutableLiveData
を使用します。LiveData
オブジェクト内のデータは読み取ることができますが、変更することはできません。ViewModel
の外部からは、データを読み取り可能にし、変更は不可能にする必要があるため、データをLiveData
として公開する必要があります。
この戦略を実行するには、Kotlin のバッキング プロパティを使用します。バッキング プロパティを使用すると、そのオブジェクト自体ではなくゲッターから返すことができます。このタスクでは、GuessTheWord アプリの score
オブジェクトと word
オブジェクトのバッキング プロパティを実装します。
バッキング プロパティをスコアと単語に追加する
GameViewModel
で、現在のscore
オブジェクトをprivate
にします。- バッキング プロパティで使用されている命名規則に従って、
score
を_score
に変更します。_score
プロパティは、内部で使用されるゲームスコアの可変バージョンになりました。 score
という名前のLiveData
型のパブリック バージョンを作成します。
// The current score
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
- 初期化エラーが表示される。このエラーは、
GameFragment
内でscore
がLiveData
参照であり、score
がセッターにアクセスできなくなったために発生します。Kotlin のゲッターとセッターについて詳しくは、ゲッターとセッターをご覧ください。
エラーを解決するには、GameViewModel
のscore
オブジェクトのget()
メソッドをオーバーライドし、バッキング プロパティ_score
を返します。
val score: LiveData<Int>
get() = _score
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)
}
...
}
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
オブジェクト word
と score
をカプセル化しました。
現在のアプリでは、ユーザーが [End Game] ボタンをタップすると、スコア画面に移動します。また、プレーヤーがすべての単語を完了したら、アプリがスコア画面に移動するようにします。プレーヤーが最後の単語を言い終えたら、ユーザーがボタンをタップしなくてもゲームが自動的に終了するようにします。
この機能を実装するには、すべての単語が表示されたときに ViewModel
からフラグメントにトリガーされて通知されるイベントが必要です。これを行うには、LiveData
オブザーバー パターンを使用してゲーム終了イベントをモデル化します。
オブザーバー パターン
オブザーバー パターンは、ソフトウェア設計パターンです。オブジェクト間の通信(オブザーバブル(観察の「対象」)とオブザーバー)を指定します。オブザーバブルは、状態の変化をオブザーバーに通知するオブジェクトです。
このアプリの LiveData
の場合、オブザーバブル(サブジェクト)は LiveData
オブジェクトであり、オブザーバーはフラグメントなどの UI コントローラのメソッドです。LiveData
内のデータが変更されるたびに、状態が変化します。LiveData
クラスは、ViewModel
からフラグメントへの通信において重要です。
ステップ 1: LiveData を使用してゲーム終了イベントを検出する
このタスクでは、LiveData
オブザーバー パターンを使用してゲーム終了イベントをモデル化します。
GameViewModel
で、_eventGameFinish
というBoolean
MutableLiveData
オブジェクトを作成します。このオブジェクトはゲーム終了イベントを保持します。_eventGameFinish
オブジェクトを初期化した後、eventGameFinish
という名前のバッキング プロパティを作成して初期化します。
// Event which triggers the end of the game
private val _eventGameFinish = MutableLiveData<Boolean>()
val eventGameFinish: LiveData<Boolean>
get() = _eventGameFinish
GameViewModel
にonGameFinish()
メソッドを追加します。このメソッドで、ゲーム終了イベントeventGameFinish
をtrue
に設定します。
/** Method for the game completed event **/
fun onGameFinish() {
_eventGameFinish.value = true
}
GameViewModel
のnextWord()
メソッド内で、単語リストが空の場合にゲームを終了します。
private fun nextWord() {
if (wordList.isEmpty()) {
onGameFinish()
} else {
//Select and remove a _word from the list
_word.value = wordList.removeAt(0)
}
}
GameFragment
のonCreateView()
内で、viewModel
を初期化した後、eventGameFinish
にオブザーバーをアタッチします。observe()
メソッドを使用します。ラムダ関数内で、gameFinished()
メソッドを呼び出します。
// Observer for the Game finished event
viewModel.eventGameFinish.observe(this, Observer<Boolean> { hasFinished ->
if (hasFinished) gameFinished()
})
- アプリを実行し、ゲームをプレイして、すべての単語をプレイします。[ゲームを終了] をタップするまでゲーム フラグメントにとどまるのではなく、スコア画面に自動的に移動します。
単語リストが空になると、eventGameFinish
が設定され、ゲーム フラグメントの関連するオブザーバー メソッドが呼び出され、アプリは画面フラグメントに移動します。 - 追加したコードによってライフサイクルの問題が発生しています。問題を把握するため、
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 回だけ表示されるはずです。フラグメントが再作成されるたびにトーストが表示されるべきではありません。この問題は次のタスクで解決します。
ステップ 2: ゲーム終了イベントをリセットする
通常、LiveData
はデータが変更された場合にのみオブザーバーに更新を配信します。オブザーバーは、非アクティブな状態からアクティブな状態に変わったときにも最新データを受け取りますが、これは例外的な動作です。
そのため、アプリでゲーム終了のトーストが繰り返しトリガーされます。画面の回転後にゲーム フラグメントが再作成されると、非アクティブ状態からアクティブ状態に移行します。フラグメント内のオブザーバーが既存の ViewModel
に再接続され、現在のデータを受信します。gameFinished()
メソッドが再度トリガーされ、トーストが表示されます。
このタスクでは、GameViewModel
の eventGameFinish
フラグをリセットして、この問題を修正し、トーストを 1 回だけ表示します。
GameViewModel
で、ゲーム終了イベント_eventGameFinish
をリセットするonGameFinishComplete()
メソッドを追加します。
/** Method for the game completed event **/
fun onGameFinishComplete() {
_eventGameFinish.value = false
}
GameFragment
のgameFinished()
の最後で、viewModel
オブジェクトのonGameFinishComplete()
を呼び出します。(ナビゲーション コードはgameFinished()
でコメントアウトしたままにしておきます)。
private fun gameFinished() {
...
viewModel.onGameFinishComplete()
}
- アプリを実行して、ゲームをプレイします。すべての単語を確認してから、デバイスの画面の向きを変更します。トーストは 1 回だけ表示されます。
GameFragment
のgameFinished()
メソッド内で、ナビゲーション コードのコメントを解除します。
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
をインポートします。
- アプリを実行して、ゲームをプレイします。すべての単語を終えた後、アプリが自動的に最終スコア画面に移動することを確認します。
その調子です。アプリは LiveData
を使用してゲーム終了イベントをトリガーし、GameViewModel
から単語リストが空であることをゲーム フラグメントに伝えます。ゲーム フラグメントはスコア フラグメントに移動します。
このタスクでは、ScoreViewModel
のスコアを LiveData
オブジェクトに変更し、オブザーバーをアタッチします。このタスクは、GameViewModel
に LiveData
を追加したときに行った作業と似ています。
これらの変更は、アプリ内のすべてのデータが LiveData
を使用するように、完全性を確保するために ScoreViewModel
に行います。
ScoreViewModel
で、score
変数の型をMutableLiveData
に変更します。慣例に従って_score
に名前を変更し、バッキング プロパティを追加します。
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
get() = _score
ScoreViewModel
のinit
ブロック内で、_score
を初期化します。init
ブロックのログは、必要に応じて削除またはそのままにできます。
init {
_score.value = finalScore
}
ScoreFragment
のonCreateView()
内で、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
をインポートします。
- アプリを実行して、ゲームをプレイします。アプリは以前と同じように動作しますが、スコアの更新に
LiveData
とオブザーバーを使用するようになります。
このタスクでは、スコア画面に [Play Again] ボタンを追加し、LiveData
イベントを使用してクリック リスナーを実装します。ボタンは、スコア画面からゲーム画面に移動するイベントをトリガーします。
アプリのスターター コードには [もう一度プレイ] ボタンが含まれていますが、このボタンは非表示になっています。
res/layout/score_fragment.xml
のplay_again_button
ボタンで、visibility
属性の値をvisible
に変更します。
<Button
android:id="@+id/play_again_button"
...
android:visibility="visible"
/>
ScoreViewModel
で、_eventPlayAgain
というBoolean
を保持するLiveData
オブジェクトを追加します。このオブジェクトは、スコア画面からゲーム画面に移動するためにLiveData
イベントを保存するために使用されます。
private val _eventPlayAgain = MutableLiveData<Boolean>()
val eventPlayAgain: LiveData<Boolean>
get() = _eventPlayAgain
ScoreViewModel
で、イベント_eventPlayAgain
を設定およびリセットするメソッドを定義します。
fun onPlayAgain() {
_eventPlayAgain.value = true
}
fun onPlayAgainComplete() {
_eventPlayAgain.value = false
}
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
をインポートします。
ScoreFragment
のonCreateView()
の中で、[PlayAgain] ボタンにクリック リスナーを追加し、viewModel
.onPlayAgain()
を呼び出します。
binding.playAgainButton.setOnClickListener { viewModel.onPlayAgain() }
- アプリを実行して、ゲームをプレイします。ゲームが終了すると、スコア画面に最終スコアと [Play Again](もう一度プレイ)ボタンが表示されます。[PlayAgain] ボタンをタップすると、アプリがゲーム画面に移動し、ゲームを再度プレイできます。
よかったですね!アプリのアーキテクチャを変更して ViewModel
で LiveData
オブジェクトを使用し、オブザーバーを LiveData
オブジェクトにアタッチしました。LiveData
は、LiveData
が保持する値が変更されるとオブザーバー オブジェクトに通知します。
Android Studio プロジェクト: GuessTheWord
LiveData
LiveData
は、ライフサイクル対応の監視可能なデータホルダー クラスであり、Android アーキテクチャ コンポーネントの 1 つです。LiveData
を使用すると、データが更新されたときに UI が自動的に更新されるようにできます。LiveData
は監視可能です。つまり、LiveData
オブジェクトに保持されているデータが変更されると、アクティビティやフラグメントなどのオブザーバーに通知されます。LiveData
にはデータが保持されます。これは、あらゆる種類のデータに使用できるラッパーです。LiveData
はライフサイクル対応です。つまり、STARTED
やRESUMED
などのアクティブなライフサイクルの状態にあるオブザーバーのみを更新します。
LiveData を追加するには
ViewModel
のデータ変数の型をLiveData
またはMutableLiveData
に変更します。
MutableLiveData
は、値を変更できる LiveData
オブジェクトです。MutableLiveData
は汎用のクラスであるため、保持するデータの種類を指定する必要があります。
LiveData
が保持するデータの値を変更するには、LiveData
変数でsetValue()
メソッドを使用します。
LiveData をカプセル化するには
ViewModel
内のLiveData
は編集可能である必要があります。ViewModel
の外部では、LiveData
は読み取り可能である必要があります。これは、Kotlin のバッキング プロパティを使用して実装できます。- Kotlin のバッキング プロパティを使用すると、そのオブジェクト自体ではなくゲッターから返すことができます。
LiveData
をカプセル化するには、ViewModel
内でprivate
MutableLiveData
を使用し、ViewModel
の外でLiveData
バッキング プロパティを返します。
Observable LiveData
LiveData
はオブザーバー パターンに従います。「オブザーバブル」はLiveData
オブジェクトで、オブザーバーはフラグメントなどの UI コントローラのメソッドです。LiveData
内でラップされたデータが変更されるたびに、UI コントローラのオブザーバー メソッドに通知が送信されます。LiveData
をオブザーバブルにするには、observe()
メソッドを使用して、オブザーバー(アクティビティやフラグメントなど)のLiveData
参照にオブザーバー オブジェクトをアタッチします。- この
LiveData
オブザーバー パターンを使用して、ViewModel
から UI コントローラに通信できます。
Udacity コース:
Android デベロッパー ドキュメント:
その他:
- Kotlin のバッキング プロパティ
このセクションでは、インストラクター主導のコースの一環として、この 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
オブジェクト
次のレッスンに進む:
このコースの他の Codelab へのリンクについては、Android Kotlin の基礎の Codelab のランディング ページをご覧ください。